diff options
Diffstat (limited to 'fpga/usrp2/opencores/i2c/rtl')
23 files changed, 3422 insertions, 0 deletions
diff --git a/fpga/usrp2/opencores/i2c/rtl/CVS/Entries b/fpga/usrp2/opencores/i2c/rtl/CVS/Entries new file mode 100644 index 000000000..354f0dfb5 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/CVS/Entries @@ -0,0 +1,2 @@ +D/verilog//// +D/vhdl//// diff --git a/fpga/usrp2/opencores/i2c/rtl/CVS/Repository b/fpga/usrp2/opencores/i2c/rtl/CVS/Repository new file mode 100644 index 000000000..cfb83efd3 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/CVS/Repository @@ -0,0 +1 @@ +i2c/rtl diff --git a/fpga/usrp2/opencores/i2c/rtl/CVS/Root b/fpga/usrp2/opencores/i2c/rtl/CVS/Root new file mode 100644 index 000000000..44b2aa23b --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@cvs.opencores.org:/cvsroot/anonymous diff --git a/fpga/usrp2/opencores/i2c/rtl/CVS/Template b/fpga/usrp2/opencores/i2c/rtl/CVS/Template new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/CVS/Template diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Entries b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Entries new file mode 100644 index 000000000..441bd81af --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Entries @@ -0,0 +1,6 @@ +/i2c_master_bit_ctrl.v/1.12/Mon Sep 4 09:08:13 2006// +/i2c_master_byte_ctrl.v/1.7/Wed Feb 18 11:40:46 2004// +/i2c_master_defines.v/1.3/Mon Nov 5 11:59:25 2001// +/i2c_master_top.v/1.11/Sun Feb 27 09:26:24 2005// +/timescale.v/1.1/Mon Sep 24 12:21:50 2001// +D diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Repository b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Repository new file mode 100644 index 000000000..49cc6cce0 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Repository @@ -0,0 +1 @@ +i2c/rtl/verilog diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Root b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Root new file mode 100644 index 000000000..44b2aa23b --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@cvs.opencores.org:/cvsroot/anonymous diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Template b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Template new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/CVS/Template diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_bit_ctrl.v b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_bit_ctrl.v new file mode 100644 index 000000000..edab94f61 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_bit_ctrl.v @@ -0,0 +1,538 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master bit-controller //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_bit_ctrl.v,v 1.12 2006/09/04 09:08:13 rherveille Exp $ +// +// $Date: 2006/09/04 09:08:13 $ +// $Revision: 1.12 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_bit_ctrl.v,v $ +// Revision 1.12 2006/09/04 09:08:13 rherveille +// fixed short scl high pulse after clock stretch +// fixed slave model not returning correct '(n)ack' signal +// +// Revision 1.11 2004/05/07 11:02:26 rherveille +// Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit. +// +// Revision 1.10 2003/08/09 07:01:33 rherveille +// Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +// Fixed a potential bug in the byte controller's host-acknowledge generation. +// +// Revision 1.9 2003/03/10 14:26:37 rherveille +// Fixed cmd_ack generation item (no bug). +// +// Revision 1.8 2003/02/05 00:06:10 rherveille +// Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles. +// +// Revision 1.7 2002/12/26 16:05:12 rherveille +// Small code simplifications +// +// Revision 1.6 2002/12/26 15:02:32 rherveille +// Core is now a Multimaster I2C controller +// +// Revision 1.5 2002/11/30 22:24:40 rherveille +// Cleaned up code +// +// Revision 1.4 2002/10/30 18:10:07 rherveille +// Fixed some reported minor start/stop generation timing issuess. +// +// Revision 1.3 2002/06/15 07:37:03 rherveille +// Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment. +// +// Revision 1.2 2001/11/05 11:59:25 rherveille +// Fixed wb_ack_o generation bug. +// Fixed bug in the byte_controller statemachine. +// Added headers. +// + +// +///////////////////////////////////// +// Bit controller section +///////////////////////////////////// +// +// Translate simple commands into SCL/SDA transitions +// Each command has 5 states, A/B/C/D/idle +// +// start: SCL ~~~~~~~~~~\____ +// SDA ~~~~~~~~\______ +// x | A | B | C | D | i +// +// repstart SCL ____/~~~~\___ +// SDA __/~~~\______ +// x | A | B | C | D | i +// +// stop SCL ____/~~~~~~~~ +// SDA ==\____/~~~~~ +// x | A | B | C | D | i +// +//- write SCL ____/~~~~\____ +// SDA ==X=========X= +// x | A | B | C | D | i +// +//- read SCL ____/~~~~\____ +// SDA XXXX=====XXXX +// x | A | B | C | D | i +// + +// Timing: Normal mode Fast mode +/////////////////////////////////////////////////////////////////////// +// Fscl 100KHz 400KHz +// Th_scl 4.0us 0.6us High period of SCL +// Tl_scl 4.7us 1.3us Low period of SCL +// Tsu:sta 4.7us 0.6us setup time for a repeated start condition +// Tsu:sto 4.0us 0.6us setup time for a stop conditon +// Tbuf 4.7us 1.3us Bus free time between a stop and start condition +// + +// synopsys translate_off +`include "timescale.v" +// synopsys translate_on + +`include "i2c_master_defines.v" + +module i2c_master_bit_ctrl( + clk, rst, nReset, + clk_cnt, ena, cmd, cmd_ack, busy, al, din, dout, + scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen + ); + + // + // inputs & outputs + // + input clk; + input rst; + input nReset; + input ena; // core enable signal + + input [15:0] clk_cnt; // clock prescale value + + input [3:0] cmd; + output cmd_ack; // command complete acknowledge + reg cmd_ack; + output busy; // i2c bus busy + reg busy; + output al; // i2c bus arbitration lost + reg al; + + input din; + output dout; + reg dout; + + // I2C lines + input scl_i; // i2c clock line input + output scl_o; // i2c clock line output + output scl_oen; // i2c clock line output enable (active low) + reg scl_oen; + input sda_i; // i2c data line input + output sda_o; // i2c data line output + output sda_oen; // i2c data line output enable (active low) + reg sda_oen; + + + // + // variable declarations + // + + reg sSCL, sSDA; // synchronized SCL and SDA inputs + reg dscl_oen; // delayed scl_oen + reg sda_chk; // check SDA output (Multi-master arbitration) + reg clk_en; // clock generation signals + wire slave_wait; +// reg [15:0] cnt = clk_cnt; // clock divider counter (simulation) + reg [15:0] cnt; // clock divider counter (synthesis) + + // state machine variable + reg [16:0] c_state; // synopsys enum_state + + // + // module body + // + + // whenever the slave is not ready it can delay the cycle by pulling SCL low + // delay scl_oen + always @(posedge clk) + dscl_oen <= #1 scl_oen; + + assign slave_wait = dscl_oen && !sSCL; + + + // generate clk enable signal + always @(posedge clk or negedge nReset) + if(~nReset) + begin + cnt <= #1 16'h0; + clk_en <= #1 1'b1; + end + else if (rst) + begin + cnt <= #1 16'h0; + clk_en <= #1 1'b1; + end + else if ( ~|cnt || !ena) + begin + cnt <= #1 clk_cnt; + clk_en <= #1 1'b1; + end + else if (slave_wait) + begin + cnt <= #1 cnt; + clk_en <= #1 1'b0; + end + else + begin + cnt <= #1 cnt - 16'h1; + clk_en <= #1 1'b0; + end + + + // generate bus status controller + reg dSCL, dSDA; + reg sta_condition; + reg sto_condition; + + // synchronize SCL and SDA inputs + // reduce metastability risc + always @(posedge clk or negedge nReset) + if (~nReset) + begin + sSCL <= #1 1'b1; + sSDA <= #1 1'b1; + + dSCL <= #1 1'b1; + dSDA <= #1 1'b1; + end + else if (rst) + begin + sSCL <= #1 1'b1; + sSDA <= #1 1'b1; + + dSCL <= #1 1'b1; + dSDA <= #1 1'b1; + end + else + begin + sSCL <= #1 scl_i; + sSDA <= #1 sda_i; + + dSCL <= #1 sSCL; + dSDA <= #1 sSDA; + end + + // detect start condition => detect falling edge on SDA while SCL is high + // detect stop condition => detect rising edge on SDA while SCL is high + always @(posedge clk or negedge nReset) + if (~nReset) + begin + sta_condition <= #1 1'b0; + sto_condition <= #1 1'b0; + end + else if (rst) + begin + sta_condition <= #1 1'b0; + sto_condition <= #1 1'b0; + end + else + begin + sta_condition <= #1 ~sSDA & dSDA & sSCL; + sto_condition <= #1 sSDA & ~dSDA & sSCL; + end + + // generate i2c bus busy signal + always @(posedge clk or negedge nReset) + if(!nReset) + busy <= #1 1'b0; + else if (rst) + busy <= #1 1'b0; + else + busy <= #1 (sta_condition | busy) & ~sto_condition; + + // generate arbitration lost signal + // aribitration lost when: + // 1) master drives SDA high, but the i2c bus is low + // 2) stop detected while not requested + reg cmd_stop; + always @(posedge clk or negedge nReset) + if (~nReset) + cmd_stop <= #1 1'b0; + else if (rst) + cmd_stop <= #1 1'b0; + else if (clk_en) + cmd_stop <= #1 cmd == `I2C_CMD_STOP; + + always @(posedge clk or negedge nReset) + if (~nReset) + al <= #1 1'b0; + else if (rst) + al <= #1 1'b0; + else + al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop); + + + // generate dout signal (store SDA on rising edge of SCL) + always @(posedge clk) + if(sSCL & ~dSCL) + dout <= #1 sSDA; + + // generate statemachine + + // nxt_state decoder + parameter [16:0] idle = 17'b0_0000_0000_0000_0000; + parameter [16:0] start_a = 17'b0_0000_0000_0000_0001; + parameter [16:0] start_b = 17'b0_0000_0000_0000_0010; + parameter [16:0] start_c = 17'b0_0000_0000_0000_0100; + parameter [16:0] start_d = 17'b0_0000_0000_0000_1000; + parameter [16:0] start_e = 17'b0_0000_0000_0001_0000; + parameter [16:0] stop_a = 17'b0_0000_0000_0010_0000; + parameter [16:0] stop_b = 17'b0_0000_0000_0100_0000; + parameter [16:0] stop_c = 17'b0_0000_0000_1000_0000; + parameter [16:0] stop_d = 17'b0_0000_0001_0000_0000; + parameter [16:0] rd_a = 17'b0_0000_0010_0000_0000; + parameter [16:0] rd_b = 17'b0_0000_0100_0000_0000; + parameter [16:0] rd_c = 17'b0_0000_1000_0000_0000; + parameter [16:0] rd_d = 17'b0_0001_0000_0000_0000; + parameter [16:0] wr_a = 17'b0_0010_0000_0000_0000; + parameter [16:0] wr_b = 17'b0_0100_0000_0000_0000; + parameter [16:0] wr_c = 17'b0_1000_0000_0000_0000; + parameter [16:0] wr_d = 17'b1_0000_0000_0000_0000; + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b0; + scl_oen <= #1 1'b1; + sda_oen <= #1 1'b1; + sda_chk <= #1 1'b0; + end + else if (rst | al) + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b0; + scl_oen <= #1 1'b1; + sda_oen <= #1 1'b1; + sda_chk <= #1 1'b0; + end + else + begin + cmd_ack <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle + + if (clk_en) + case (c_state) // synopsys full_case parallel_case + // idle state + idle: + begin + case (cmd) // synopsys full_case parallel_case + `I2C_CMD_START: + c_state <= #1 start_a; + + `I2C_CMD_STOP: + c_state <= #1 stop_a; + + `I2C_CMD_WRITE: + c_state <= #1 wr_a; + + `I2C_CMD_READ: + c_state <= #1 rd_a; + + default: + c_state <= #1 idle; + endcase + + scl_oen <= #1 scl_oen; // keep SCL in same state + sda_oen <= #1 sda_oen; // keep SDA in same state + sda_chk <= #1 1'b0; // don't check SDA output + end + + // start + start_a: + begin + c_state <= #1 start_b; + scl_oen <= #1 scl_oen; // keep SCL in same state + sda_oen <= #1 1'b1; // set SDA high + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_b: + begin + c_state <= #1 start_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 1'b1; // keep SDA high + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_c: + begin + c_state <= #1 start_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b0; // set SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_d: + begin + c_state <= #1 start_e; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_e: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b0; // set SCL low + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + // stop + stop_a: + begin + c_state <= #1 stop_b; + scl_oen <= #1 1'b0; // keep SCL low + sda_oen <= #1 1'b0; // set SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + stop_b: + begin + c_state <= #1 stop_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + stop_c: + begin + c_state <= #1 stop_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + stop_d: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b1; // set SDA high + sda_chk <= #1 1'b0; // don't check SDA output + end + + // read + rd_a: + begin + c_state <= #1 rd_b; + scl_oen <= #1 1'b0; // keep SCL low + sda_oen <= #1 1'b1; // tri-state SDA + sda_chk <= #1 1'b0; // don't check SDA output + end + + rd_b: + begin + c_state <= #1 rd_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 1'b1; // keep SDA tri-stated + sda_chk <= #1 1'b0; // don't check SDA output + end + + rd_c: + begin + c_state <= #1 rd_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b1; // keep SDA tri-stated + sda_chk <= #1 1'b0; // don't check SDA output + end + + rd_d: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b0; // set SCL low + sda_oen <= #1 1'b1; // keep SDA tri-stated + sda_chk <= #1 1'b0; // don't check SDA output + end + + // write + wr_a: + begin + c_state <= #1 wr_b; + scl_oen <= #1 1'b0; // keep SCL low + sda_oen <= #1 din; // set SDA + sda_chk <= #1 1'b0; // don't check SDA output (SCL low) + end + + wr_b: + begin + c_state <= #1 wr_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 din; // keep SDA + sda_chk <= #1 1'b1; // check SDA output + end + + wr_c: + begin + c_state <= #1 wr_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 din; + sda_chk <= #1 1'b1; // check SDA output + end + + wr_d: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b0; // set SCL low + sda_oen <= #1 din; + sda_chk <= #1 1'b0; // don't check SDA output (SCL low) + end + + endcase + end + + + // assign scl and sda output (always gnd) + assign scl_o = 1'b0; + assign sda_o = 1'b0; + +endmodule diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_byte_ctrl.v b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_byte_ctrl.v new file mode 100644 index 000000000..d091d1e36 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_byte_ctrl.v @@ -0,0 +1,344 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master byte-controller //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_byte_ctrl.v,v 1.7 2004/02/18 11:40:46 rherveille Exp $ +// +// $Date: 2004/02/18 11:40:46 $ +// $Revision: 1.7 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_byte_ctrl.v,v $ +// Revision 1.7 2004/02/18 11:40:46 rherveille +// Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command. +// +// Revision 1.6 2003/08/09 07:01:33 rherveille +// Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +// Fixed a potential bug in the byte controller's host-acknowledge generation. +// +// Revision 1.5 2002/12/26 15:02:32 rherveille +// Core is now a Multimaster I2C controller +// +// Revision 1.4 2002/11/30 22:24:40 rherveille +// Cleaned up code +// +// Revision 1.3 2001/11/05 11:59:25 rherveille +// Fixed wb_ack_o generation bug. +// Fixed bug in the byte_controller statemachine. +// Added headers. +// + +// synopsys translate_off +`include "timescale.v" +// synopsys translate_on + +`include "i2c_master_defines.v" + +module i2c_master_byte_ctrl ( + clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din, + cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen ); + + // + // inputs & outputs + // + input clk; // master clock + input rst; // synchronous active high reset + input nReset; // asynchronous active low reset + input ena; // core enable signal + + input [15:0] clk_cnt; // 4x SCL + + // control inputs + input start; + input stop; + input read; + input write; + input ack_in; + input [7:0] din; + + // status outputs + output cmd_ack; + reg cmd_ack; + output ack_out; + reg ack_out; + output i2c_busy; + output i2c_al; + output [7:0] dout; + + // I2C signals + input scl_i; + output scl_o; + output scl_oen; + input sda_i; + output sda_o; + output sda_oen; + + + // + // Variable declarations + // + + // statemachine + parameter [4:0] ST_IDLE = 5'b0_0000; + parameter [4:0] ST_START = 5'b0_0001; + parameter [4:0] ST_READ = 5'b0_0010; + parameter [4:0] ST_WRITE = 5'b0_0100; + parameter [4:0] ST_ACK = 5'b0_1000; + parameter [4:0] ST_STOP = 5'b1_0000; + + // signals for bit_controller + reg [3:0] core_cmd; + reg core_txd; + wire core_ack, core_rxd; + + // signals for shift register + reg [7:0] sr; //8bit shift register + reg shift, ld; + + // signals for state machine + wire go; + reg [2:0] dcnt; + wire cnt_done; + + // + // Module body + // + + // hookup bit_controller + i2c_master_bit_ctrl bit_controller ( + .clk ( clk ), + .rst ( rst ), + .nReset ( nReset ), + .ena ( ena ), + .clk_cnt ( clk_cnt ), + .cmd ( core_cmd ), + .cmd_ack ( core_ack ), + .busy ( i2c_busy ), + .al ( i2c_al ), + .din ( core_txd ), + .dout ( core_rxd ), + .scl_i ( scl_i ), + .scl_o ( scl_o ), + .scl_oen ( scl_oen ), + .sda_i ( sda_i ), + .sda_o ( sda_o ), + .sda_oen ( sda_oen ) + ); + + // generate go-signal + assign go = (read | write | stop) & ~cmd_ack; + + // assign dout output to shift-register + assign dout = sr; + + // generate shift register + always @(posedge clk or negedge nReset) + if (!nReset) + sr <= #1 8'h0; + else if (rst) + sr <= #1 8'h0; + else if (ld) + sr <= #1 din; + else if (shift) + sr <= #1 {sr[6:0], core_rxd}; + + // generate counter + always @(posedge clk or negedge nReset) + if (!nReset) + dcnt <= #1 3'h0; + else if (rst) + dcnt <= #1 3'h0; + else if (ld) + dcnt <= #1 3'h7; + else if (shift) + dcnt <= #1 dcnt - 3'h1; + + assign cnt_done = ~(|dcnt); + + // + // state machine + // + reg [4:0] c_state; // synopsis enum_state + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + core_cmd <= #1 `I2C_CMD_NOP; + core_txd <= #1 1'b0; + shift <= #1 1'b0; + ld <= #1 1'b0; + cmd_ack <= #1 1'b0; + c_state <= #1 ST_IDLE; + ack_out <= #1 1'b0; + end + else if (rst | i2c_al) + begin + core_cmd <= #1 `I2C_CMD_NOP; + core_txd <= #1 1'b0; + shift <= #1 1'b0; + ld <= #1 1'b0; + cmd_ack <= #1 1'b0; + c_state <= #1 ST_IDLE; + ack_out <= #1 1'b0; + end + else + begin + // initially reset all signals + core_txd <= #1 sr[7]; + shift <= #1 1'b0; + ld <= #1 1'b0; + cmd_ack <= #1 1'b0; + + case (c_state) // synopsys full_case parallel_case + ST_IDLE: + if (go) + begin + if (start) + begin + c_state <= #1 ST_START; + core_cmd <= #1 `I2C_CMD_START; + end + else if (read) + begin + c_state <= #1 ST_READ; + core_cmd <= #1 `I2C_CMD_READ; + end + else if (write) + begin + c_state <= #1 ST_WRITE; + core_cmd <= #1 `I2C_CMD_WRITE; + end + else // stop + begin + c_state <= #1 ST_STOP; + core_cmd <= #1 `I2C_CMD_STOP; + end + + ld <= #1 1'b1; + end + + ST_START: + if (core_ack) + begin + if (read) + begin + c_state <= #1 ST_READ; + core_cmd <= #1 `I2C_CMD_READ; + end + else + begin + c_state <= #1 ST_WRITE; + core_cmd <= #1 `I2C_CMD_WRITE; + end + + ld <= #1 1'b1; + end + + ST_WRITE: + if (core_ack) + if (cnt_done) + begin + c_state <= #1 ST_ACK; + core_cmd <= #1 `I2C_CMD_READ; + end + else + begin + c_state <= #1 ST_WRITE; // stay in same state + core_cmd <= #1 `I2C_CMD_WRITE; // write next bit + shift <= #1 1'b1; + end + + ST_READ: + if (core_ack) + begin + if (cnt_done) + begin + c_state <= #1 ST_ACK; + core_cmd <= #1 `I2C_CMD_WRITE; + end + else + begin + c_state <= #1 ST_READ; // stay in same state + core_cmd <= #1 `I2C_CMD_READ; // read next bit + end + + shift <= #1 1'b1; + core_txd <= #1 ack_in; + end + + ST_ACK: + if (core_ack) + begin + if (stop) + begin + c_state <= #1 ST_STOP; + core_cmd <= #1 `I2C_CMD_STOP; + end + else + begin + c_state <= #1 ST_IDLE; + core_cmd <= #1 `I2C_CMD_NOP; + + // generate command acknowledge signal + cmd_ack <= #1 1'b1; + end + + // assign ack_out output to bit_controller_rxd (contains last received bit) + ack_out <= #1 core_rxd; + + core_txd <= #1 1'b1; + end + else + core_txd <= #1 ack_in; + + ST_STOP: + if (core_ack) + begin + c_state <= #1 ST_IDLE; + core_cmd <= #1 `I2C_CMD_NOP; + + // generate command acknowledge signal + cmd_ack <= #1 1'b1; + end + + endcase + end +endmodule diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_defines.v b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_defines.v new file mode 100644 index 000000000..ee3b694fa --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_defines.v @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master controller defines //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_defines.v,v 1.3 2001/11/05 11:59:25 rherveille Exp $ +// +// $Date: 2001/11/05 11:59:25 $ +// $Revision: 1.3 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_defines.v,v $ +// Revision 1.3 2001/11/05 11:59:25 rherveille +// Fixed wb_ack_o generation bug. +// Fixed bug in the byte_controller statemachine. +// Added headers. +// + + +// I2C registers wishbone addresses + +// bitcontroller states +`define I2C_CMD_NOP 4'b0000 +`define I2C_CMD_START 4'b0001 +`define I2C_CMD_STOP 4'b0010 +`define I2C_CMD_WRITE 4'b0100 +`define I2C_CMD_READ 4'b1000 diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_top.v b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_top.v new file mode 100644 index 000000000..30689bd70 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/i2c_master_top.v @@ -0,0 +1,301 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE revB.2 compliant I2C Master controller Top-level //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_top.v,v 1.11 2005/02/27 09:26:24 rherveille Exp $ +// +// $Date: 2005/02/27 09:26:24 $ +// $Revision: 1.11 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_top.v,v $ +// Revision 1.11 2005/02/27 09:26:24 rherveille +// Fixed register overwrite issue. +// Removed full_case pragma, replaced it by a default statement. +// +// Revision 1.10 2003/09/01 10:34:38 rherveille +// Fix a blocking vs. non-blocking error in the wb_dat output mux. +// +// Revision 1.9 2003/01/09 16:44:45 rherveille +// Fixed a bug in the Command Register declaration. +// +// Revision 1.8 2002/12/26 16:05:12 rherveille +// Small code simplifications +// +// Revision 1.7 2002/12/26 15:02:32 rherveille +// Core is now a Multimaster I2C controller +// +// Revision 1.6 2002/11/30 22:24:40 rherveille +// Cleaned up code +// +// Revision 1.5 2001/11/10 10:52:55 rherveille +// Changed PRER reset value from 0x0000 to 0xffff, conform specs. +// + +// synopsys translate_off +`include "timescale.v" +// synopsys translate_on + +`include "i2c_master_defines.v" + +module i2c_master_top( + wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o, + wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o, + scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o ); + + // parameters + parameter ARST_LVL = 1'b0; // asynchronous reset level + + // + // inputs & outputs + // + + // wishbone signals + input wb_clk_i; // master clock input + input wb_rst_i; // synchronous active high reset + input arst_i; // asynchronous reset + input [2:0] wb_adr_i; // lower address bits + input [7:0] wb_dat_i; // databus input + output [7:0] wb_dat_o; // databus output + input wb_we_i; // write enable input + input wb_stb_i; // stobe/core select signal + input wb_cyc_i; // valid bus cycle input + output wb_ack_o; // bus cycle acknowledge output + output wb_inta_o; // interrupt request signal output + + reg [7:0] wb_dat_o; + reg wb_ack_o; + reg wb_inta_o; + + // I2C signals + // i2c clock line + input scl_pad_i; // SCL-line input + output scl_pad_o; // SCL-line output (always 1'b0) + output scl_padoen_o; // SCL-line output enable (active low) + + // i2c data line + input sda_pad_i; // SDA-line input + output sda_pad_o; // SDA-line output (always 1'b0) + output sda_padoen_o; // SDA-line output enable (active low) + + + // + // variable declarations + // + + // registers + reg [15:0] prer; // clock prescale register + reg [ 7:0] ctr; // control register + reg [ 7:0] txr; // transmit register + wire [ 7:0] rxr; // receive register + reg [ 7:0] cr; // command register + wire [ 7:0] sr; // status register + + // done signal: command completed, clear command register + wire done; + + // core enable signal + wire core_en; + wire ien; + + // status register signals + wire irxack; + reg rxack; // received aknowledge from slave + reg tip; // transfer in progress + reg irq_flag; // interrupt pending flag + wire i2c_busy; // bus busy (start signal detected) + wire i2c_al; // i2c bus arbitration lost + reg al; // status register arbitration lost bit + + // + // module body + // + + // generate internal reset + wire rst_i = arst_i ^ ARST_LVL; + + // generate wishbone signals + wire wb_wacc = wb_cyc_i & wb_stb_i & wb_we_i; + + // generate acknowledge output signal + always @(posedge wb_clk_i) + wb_ack_o <= #1 wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored + + // assign DAT_O + always @(posedge wb_clk_i) + begin + case (wb_adr_i) // synopsis parallel_case + 3'b000: wb_dat_o <= #1 prer[ 7:0]; + 3'b001: wb_dat_o <= #1 prer[15:8]; + 3'b010: wb_dat_o <= #1 ctr; + 3'b011: wb_dat_o <= #1 rxr; // write is transmit register (txr) + 3'b100: wb_dat_o <= #1 sr; // write is command register (cr) + 3'b101: wb_dat_o <= #1 txr; + 3'b110: wb_dat_o <= #1 cr; + 3'b111: wb_dat_o <= #1 0; // reserved + endcase + end + + // generate registers + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + begin + prer <= #1 16'hffff; + ctr <= #1 8'h0; + txr <= #1 8'h0; + end + else if (wb_rst_i) + begin + prer <= #1 16'hffff; + ctr <= #1 8'h0; + txr <= #1 8'h0; + end + else + if (wb_wacc) + case (wb_adr_i) // synopsis parallel_case + 3'b000 : prer [ 7:0] <= #1 wb_dat_i; + 3'b001 : prer [15:8] <= #1 wb_dat_i; + 3'b010 : ctr <= #1 wb_dat_i; + 3'b011 : txr <= #1 wb_dat_i; + default: ; + endcase + + // generate command register (special case) + always @(posedge wb_clk_i or negedge rst_i) + if (~rst_i) + cr <= #1 8'h0; + else if (wb_rst_i) + cr <= #1 8'h0; + else if (wb_wacc) + begin + if (core_en & (wb_adr_i == 3'b100) ) + cr <= #1 wb_dat_i; + end + else + begin + if (done | i2c_al) + cr[7:4] <= #1 4'h0; // clear command bits when done + // or when aribitration lost + cr[2:1] <= #1 2'b0; // reserved bits + cr[0] <= #1 2'b0; // clear IRQ_ACK bit + end + + + // decode command register + wire sta = cr[7]; + wire sto = cr[6]; + wire rd = cr[5]; + wire wr = cr[4]; + wire ack = cr[3]; + wire iack = cr[0]; + + // decode control register + assign core_en = ctr[7]; + assign ien = ctr[6]; + + // hookup byte controller block + i2c_master_byte_ctrl byte_controller ( + .clk ( wb_clk_i ), + .rst ( wb_rst_i ), + .nReset ( rst_i ), + .ena ( core_en ), + .clk_cnt ( prer ), + .start ( sta ), + .stop ( sto ), + .read ( rd ), + .write ( wr ), + .ack_in ( ack ), + .din ( txr ), + .cmd_ack ( done ), + .ack_out ( irxack ), + .dout ( rxr ), + .i2c_busy ( i2c_busy ), + .i2c_al ( i2c_al ), + .scl_i ( scl_pad_i ), + .scl_o ( scl_pad_o ), + .scl_oen ( scl_padoen_o ), + .sda_i ( sda_pad_i ), + .sda_o ( sda_pad_o ), + .sda_oen ( sda_padoen_o ) + ); + + // status register block + interrupt request signal + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + begin + al <= #1 1'b0; + rxack <= #1 1'b0; + tip <= #1 1'b0; + irq_flag <= #1 1'b0; + end + else if (wb_rst_i) + begin + al <= #1 1'b0; + rxack <= #1 1'b0; + tip <= #1 1'b0; + irq_flag <= #1 1'b0; + end + else + begin + al <= #1 i2c_al | (al & ~sta); + rxack <= #1 irxack; + tip <= #1 (rd | wr); + irq_flag <= #1 (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated + end + + // generate interrupt request signals + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + wb_inta_o <= #1 1'b0; + else if (wb_rst_i) + wb_inta_o <= #1 1'b0; + else + wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set) + + // assign status register bits + assign sr[7] = rxack; + assign sr[6] = i2c_busy; + assign sr[5] = al; + assign sr[4:2] = 3'h0; // reserved + assign sr[1] = tip; + assign sr[0] = irq_flag; + +endmodule diff --git a/fpga/usrp2/opencores/i2c/rtl/verilog/timescale.v b/fpga/usrp2/opencores/i2c/rtl/verilog/timescale.v new file mode 100644 index 000000000..60d4ecbd1 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/verilog/timescale.v @@ -0,0 +1,2 @@ +`timescale 1ns / 10ps + diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Entries b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Entries new file mode 100644 index 000000000..2a33278f7 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Entries @@ -0,0 +1,7 @@ +/I2C.VHD/1.1/Mon Sep 24 12:21:51 2001// +/i2c_master_bit_ctrl.vhd/1.14/Wed Oct 11 12:10:13 2006// +/i2c_master_byte_ctrl.vhd/1.5/Wed Feb 18 11:41:48 2004// +/i2c_master_top.vhd/1.7/Sun Mar 14 10:17:03 2004// +/readme/1.2/Sat Nov 30 22:25:47 2002// +/tst_ds1621.vhd/1.1/Mon Sep 24 12:21:51 2001// +D diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Repository b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Repository new file mode 100644 index 000000000..c210ff4e3 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Repository @@ -0,0 +1 @@ +i2c/rtl/vhdl diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Root b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Root new file mode 100644 index 000000000..44b2aa23b --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@cvs.opencores.org:/cvsroot/anonymous diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Template b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Template new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Template diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/I2C.VHD b/fpga/usrp2/opencores/i2c/rtl/vhdl/I2C.VHD new file mode 100644 index 000000000..64d1eb656 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/I2C.VHD @@ -0,0 +1,620 @@ +-- +-- Simple I2C controller +-- +-- 1) No multimaster +-- 2) No slave mode +-- 3) No fifo's +-- +-- notes: +-- Every command is acknowledged. Do not set a new command before previous is acknowledged. +-- Dout is available 1 clock cycle later as cmd_ack +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +package I2C is + component simple_i2c is + port ( + clk : in std_logic; + ena : in std_logic; + nReset : in std_logic; + + clk_cnt : in unsigned(7 downto 0); -- 4x SCL + + -- input signals + start, + stop, + read, + write, + ack_in : std_logic; + Din : in std_logic_vector(7 downto 0); + + -- output signals + cmd_ack : out std_logic; + ack_out : out std_logic; + Dout : out std_logic_vector(7 downto 0); + + -- i2c signals + SCL : inout std_logic; + SDA : inout std_logic + ); + end component simple_i2c; +end package I2C; + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +entity simple_i2c is + port ( + clk : in std_logic; + ena : in std_logic; + nReset : in std_logic; + + clk_cnt : in unsigned(7 downto 0); -- 4x SCL + + -- input signals + start, + stop, + read, + write, + ack_in : std_logic; + Din : in std_logic_vector(7 downto 0); + + -- output signals + cmd_ack : out std_logic; + ack_out : out std_logic; + Dout : out std_logic_vector(7 downto 0); + + -- i2c signals + SCL : inout std_logic; + SDA : inout std_logic + ); +end entity simple_i2c; + +architecture structural of simple_i2c is + component i2c_core is + port ( + clk : in std_logic; + nReset : in std_logic; + + clk_cnt : in unsigned(7 downto 0); + + cmd : in std_logic_vector(2 downto 0); + cmd_ack : out std_logic; + busy : out std_logic; + + Din : in std_logic; + Dout : out std_logic; + + SCL : inout std_logic; + SDA : inout std_logic + ); + end component i2c_core; + + -- commands for i2c_core + constant CMD_NOP : std_logic_vector(2 downto 0) := "000"; + constant CMD_START : std_logic_vector(2 downto 0) := "010"; + constant CMD_STOP : std_logic_vector(2 downto 0) := "011"; + constant CMD_READ : std_logic_vector(2 downto 0) := "100"; + constant CMD_WRITE : std_logic_vector(2 downto 0) := "101"; + + -- signals for i2c_core + signal core_cmd : std_logic_vector(2 downto 0); + signal core_ack, core_busy, core_txd, core_rxd : std_logic; + + -- signals for shift register + signal sr : std_logic_vector(7 downto 0); -- 8bit shift register + signal shift, ld : std_logic; + + -- signals for state machine + signal go, host_ack : std_logic; +begin + -- hookup i2c core + u1: i2c_core port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_busy, core_txd, core_rxd, SCL, SDA); + + -- generate host-command-acknowledge + cmd_ack <= host_ack; + + -- generate go-signal + go <= (read or write) and not host_ack; + + -- assign Dout output to shift-register + Dout <= sr; + + -- assign ack_out output to core_rxd (contains last received bit) + ack_out <= core_rxd; + + -- generate shift register + shift_register: process(clk) + begin + if (clk'event and clk = '1') then + if (ld = '1') then + sr <= din; + elsif (shift = '1') then + sr <= (sr(6 downto 0) & core_rxd); + end if; + end if; + end process shift_register; + + -- + -- state machine + -- + statemachine : block + type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop); + signal state : states; + signal dcnt : unsigned(2 downto 0); + begin + -- + -- command interpreter, translate complex commands into simpler I2C commands + -- + nxt_state_decoder: process(clk, nReset, state) + variable nxt_state : states; + variable idcnt : unsigned(2 downto 0); + variable ihost_ack : std_logic; + variable icore_cmd : std_logic_vector(2 downto 0); + variable icore_txd : std_logic; + variable ishift, iload : std_logic; + begin + -- 8 databits (1byte) of data to shift-in/out + idcnt := dcnt; + + -- no acknowledge (until command complete) + ihost_ack := '0'; + + icore_txd := core_txd; + + -- keep current command to i2c_core + icore_cmd := core_cmd; + + -- no shifting or loading of shift-register + ishift := '0'; + iload := '0'; + + -- keep current state; + nxt_state := state; + case state is + when st_idle => + if (go = '1') then + if (start = '1') then + nxt_state := st_start; + icore_cmd := CMD_START; + elsif (read = '1') then + nxt_state := st_read; + icore_cmd := CMD_READ; + idcnt := "111"; + else + nxt_state := st_write; + icore_cmd := CMD_WRITE; + idcnt := "111"; + iload := '1'; + end if; + end if; + + when st_start => + if (core_ack = '1') then + if (read = '1') then + nxt_state := st_read; + icore_cmd := CMD_READ; + idcnt := "111"; + else + nxt_state := st_write; + icore_cmd := CMD_WRITE; + idcnt := "111"; + iload := '1'; + end if; + end if; + + when st_write => + if (core_ack = '1') then + idcnt := dcnt -1; -- count down Data_counter + icore_txd := sr(7); + if (dcnt = 0) then + nxt_state := st_ack; + icore_cmd := CMD_READ; + else + ishift := '1'; +-- icore_txd := sr(7); + end if; + end if; + + when st_read => + if (core_ack = '1') then + idcnt := dcnt -1; -- count down Data_counter + ishift := '1'; + if (dcnt = 0) then + nxt_state := st_ack; + icore_cmd := CMD_WRITE; + icore_txd := ack_in; + end if; + end if; + + when st_ack => + if (core_ack = '1') then + -- generate command acknowledge signal + ihost_ack := '1'; + + -- Perform an additional shift, needed for 'read' (store last received bit in shift register) + ishift := '1'; + + -- check for stop; Should a STOP command be generated ? + if (stop = '1') then + nxt_state := st_stop; + icore_cmd := CMD_STOP; + else + nxt_state := st_idle; + icore_cmd := CMD_NOP; + end if; + end if; + + when st_stop => + if (core_ack = '1') then + nxt_state := st_idle; + icore_cmd := CMD_NOP; + end if; + + when others => -- illegal states + nxt_state := st_idle; + icore_cmd := CMD_NOP; + end case; + + -- generate registers + if (nReset = '0') then + core_cmd <= CMD_NOP; + core_txd <= '0'; + + shift <= '0'; + ld <= '0'; + + dcnt <= "111"; + host_ack <= '0'; + + state <= st_idle; + elsif (clk'event and clk = '1') then + if (ena = '1') then + state <= nxt_state; + + dcnt <= idcnt; + shift <= ishift; + ld <= iload; + + core_cmd <= icore_cmd; + core_txd <= icore_txd; + + host_ack <= ihost_ack; + end if; + end if; + end process nxt_state_decoder; + + end block statemachine; + +end architecture structural; + + +-- +-- +-- I2C Core +-- +-- Translate simple commands into SCL/SDA transitions +-- Each command has 5 states, A/B/C/D/idle +-- +-- start: SCL ~~~~~~~~~~\____ +-- SDA ~~~~~~~~\______ +-- x | A | B | C | D | i +-- +-- repstart SCL ____/~~~~\___ +-- SDA __/~~~\______ +-- x | A | B | C | D | i +-- +-- stop SCL ____/~~~~~~~~ +-- SDA ==\____/~~~~~ +-- x | A | B | C | D | i +-- +--- write SCL ____/~~~~\____ +-- SDA ==X=========X= +-- x | A | B | C | D | i +-- +--- read SCL ____/~~~~\____ +-- SDA XXXX=====XXXX +-- x | A | B | C | D | i +-- + +-- Timing: Normal mode Fast mode +----------------------------------------------------------------- +-- Fscl 100KHz 400KHz +-- Th_scl 4.0us 0.6us High period of SCL +-- Tl_scl 4.7us 1.3us Low period of SCL +-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition +-- Tsu:sto 4.0us 0.6us setup time for a stop conditon +-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +entity i2c_core is + port ( + clk : in std_logic; + nReset : in std_logic; + + clk_cnt : in unsigned(7 downto 0); + + cmd : in std_logic_vector(2 downto 0); + cmd_ack : out std_logic; + busy : out std_logic; + + Din : in std_logic; + Dout : out std_logic; + + SCL : inout std_logic; + SDA : inout std_logic + ); +end entity i2c_core; + +architecture structural of i2c_core is + constant CMD_NOP : std_logic_vector(2 downto 0) := "000"; + constant CMD_START : std_logic_vector(2 downto 0) := "010"; + constant CMD_STOP : std_logic_vector(2 downto 0) := "011"; + constant CMD_READ : std_logic_vector(2 downto 0) := "100"; + constant CMD_WRITE : std_logic_vector(2 downto 0) := "101"; + + type cmds is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d); + signal state : cmds; + signal SDAo, SCLo : std_logic; + signal txd : std_logic; + signal clk_en, slave_wait :std_logic; + signal cnt : unsigned(7 downto 0) := clk_cnt; +begin + -- whenever the slave is not ready it can delay the cycle by pulling SCL low + slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0'; + + -- generate clk enable signal + gen_clken: process(clk, nReset) + begin + if (nReset = '0') then + cnt <= (others => '0'); + clk_en <= '1'; --'0'; + elsif (clk'event and clk = '1') then + if (cnt = 0) then + clk_en <= '1'; + cnt <= clk_cnt; + else + if (slave_wait = '0') then + cnt <= cnt -1; + end if; + clk_en <= '0'; + end if; + end if; + end process gen_clken; + + -- generate statemachine + nxt_state_decoder : process (clk, nReset, state, cmd, SDA) + variable nxt_state : cmds; + variable icmd_ack, ibusy, store_sda : std_logic; + variable itxd : std_logic; + begin + + nxt_state := state; + + icmd_ack := '0'; -- default no acknowledge + ibusy := '1'; -- default busy + + store_sda := '0'; + + itxd := txd; + + case (state) is + -- idle + when idle => + case cmd is + when CMD_START => + nxt_state := start_a; + icmd_ack := '1'; -- command completed + + when CMD_STOP => + nxt_state := stop_a; + icmd_ack := '1'; -- command completed + + when CMD_WRITE => + nxt_state := wr_a; + icmd_ack := '1'; -- command completed + itxd := Din; + + when CMD_READ => + nxt_state := rd_a; + icmd_ack := '1'; -- command completed + + when others => + nxt_state := idle; +-- don't acknowledge NOP command icmd_ack := '1'; -- command completed + ibusy := '0'; + end case; + + -- start + when start_a => + nxt_state := start_b; + + when start_b => + nxt_state := start_c; + + when start_c => + nxt_state := start_d; + + when start_d => + nxt_state := idle; + ibusy := '0'; -- not busy when idle + + + -- stop + when stop_a => + nxt_state := stop_b; + + when stop_b => + nxt_state := stop_c; + + when stop_c => +-- nxt_state := stop_d; + +-- when stop_d => + nxt_state := idle; + ibusy := '0'; -- not busy when idle + + -- read + when rd_a => + nxt_state := rd_b; + + when rd_b => + nxt_state := rd_c; + + when rd_c => + nxt_state := rd_d; + store_sda := '1'; + + when rd_d => + nxt_state := idle; + ibusy := '0'; -- not busy when idle + + -- write + when wr_a => + nxt_state := wr_b; + + when wr_b => + nxt_state := wr_c; + + when wr_c => + nxt_state := wr_d; + + when wr_d => + nxt_state := idle; + ibusy := '0'; -- not busy when idle + + end case; + + -- generate regs + if (nReset = '0') then + state <= idle; + cmd_ack <= '0'; + busy <= '0'; + txd <= '0'; + Dout <= '0'; + elsif (clk'event and clk = '1') then + if (clk_en = '1') then + state <= nxt_state; + busy <= ibusy; + + txd <= itxd; + if (store_sda = '1') then + Dout <= SDA; + end if; + end if; + + cmd_ack <= icmd_ack and clk_en; + end if; + end process nxt_state_decoder; + + -- + -- convert states to SCL and SDA signals + -- + output_decoder: process (clk, nReset, state) + variable iscl, isda : std_logic; + begin + case (state) is + when idle => + iscl := SCLo; -- keep SCL in same state + isda := SDA; -- keep SDA in same state + + -- start + when start_a => + iscl := SCLo; -- keep SCL in same state (for repeated start) + isda := '1'; -- set SDA high + + when start_b => + iscl := '1'; -- set SCL high + isda := '1'; -- keep SDA high + + when start_c => + iscl := '1'; -- keep SCL high + isda := '0'; -- sel SDA low + + when start_d => + iscl := '0'; -- set SCL low + isda := '0'; -- keep SDA low + + -- stop + when stop_a => + iscl := '0'; -- keep SCL disabled + isda := '0'; -- set SDA low + + when stop_b => + iscl := '1'; -- set SCL high + isda := '0'; -- keep SDA low + + when stop_c => + iscl := '1'; -- keep SCL high + isda := '1'; -- set SDA high + + -- write + when wr_a => + iscl := '0'; -- keep SCL low +-- isda := txd; -- set SDA + isda := Din; + + when wr_b => + iscl := '1'; -- set SCL high +-- isda := txd; -- set SDA + isda := Din; + + when wr_c => + iscl := '1'; -- keep SCL high +-- isda := txd; -- set SDA + isda := Din; + + when wr_d => + iscl := '0'; -- set SCL low +-- isda := txd; -- set SDA + isda := Din; + + -- read + when rd_a => + iscl := '0'; -- keep SCL low + isda := '1'; -- tri-state SDA + + when rd_b => + iscl := '1'; -- set SCL high + isda := '1'; -- tri-state SDA + + when rd_c => + iscl := '1'; -- keep SCL high + isda := '1'; -- tri-state SDA + + when rd_d => + iscl := '0'; -- set SCL low + isda := '1'; -- tri-state SDA + end case; + + -- generate registers + if (nReset = '0') then + SCLo <= '1'; + SDAo <= '1'; + elsif (clk'event and clk = '1') then + if (clk_en = '1') then + SCLo <= iscl; + SDAo <= isda; + end if; + end if; + end process output_decoder; + + SCL <= '0' when (SCLo = '0') else 'Z'; -- since SCL is externally pulled-up convert a '1' to a 'Z'(tri-state) + SDA <= '0' when (SDAo = '0') else 'Z'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state) +-- SCL <= SCLo; +-- SDA <= SDAo; + +end architecture structural; + + + + diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_bit_ctrl.vhd b/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_bit_ctrl.vhd new file mode 100644 index 000000000..1b8eb96d2 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_bit_ctrl.vhd @@ -0,0 +1,495 @@ +--------------------------------------------------------------------- +---- ---- +---- WISHBONE revB2 I2C Master Core; bit-controller ---- +---- ---- +---- ---- +---- Author: Richard Herveille ---- +---- richard@asics.ws ---- +---- www.asics.ws ---- +---- ---- +---- Downloaded from: http://www.opencores.org/projects/i2c/ ---- +---- ---- +--------------------------------------------------------------------- +---- ---- +---- Copyright (C) 2000 Richard Herveille ---- +---- richard@asics.ws ---- +---- ---- +---- This source file may be used and distributed without ---- +---- restriction provided that this copyright statement is not ---- +---- removed from the file and that any derivative work contains ---- +---- the original copyright notice and the associated disclaimer.---- +---- ---- +---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ---- +---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ---- +---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ---- +---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ---- +---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ---- +---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---- +---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ---- +---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ---- +---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ---- +---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---- +---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ---- +---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ---- +---- POSSIBILITY OF SUCH DAMAGE. ---- +---- ---- +--------------------------------------------------------------------- + +-- CVS Log +-- +-- $Id: i2c_master_bit_ctrl.vhd,v 1.14 2006/10/11 12:10:13 rherveille Exp $ +-- +-- $Date: 2006/10/11 12:10:13 $ +-- $Revision: 1.14 $ +-- $Author: rherveille $ +-- $Locker: $ +-- $State: Exp $ +-- +-- Change History: +-- $Log: i2c_master_bit_ctrl.vhd,v $ +-- Revision 1.14 2006/10/11 12:10:13 rherveille +-- Added missing semicolons ';' on endif +-- +-- Revision 1.13 2006/10/06 10:48:24 rherveille +-- fixed short scl high pulse after clock stretch +-- +-- Revision 1.12 2004/05/07 11:53:31 rherveille +-- Fixed previous fix :) Made a variable vs signal mistake. +-- +-- Revision 1.11 2004/05/07 11:04:00 rherveille +-- Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit. +-- +-- Revision 1.10 2004/02/27 07:49:43 rherveille +-- Fixed a bug in the arbitration-lost signal generation. VHDL version only. +-- +-- Revision 1.9 2003/08/12 14:48:37 rherveille +-- Forgot an 'end if' :-/ +-- +-- Revision 1.8 2003/08/09 07:01:13 rherveille +-- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +-- Fixed a potential bug in the byte controller's host-acknowledge generation. +-- +-- Revision 1.7 2003/02/05 00:06:02 rherveille +-- Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles. +-- +-- Revision 1.6 2003/02/01 02:03:06 rherveille +-- Fixed a few 'arbitration lost' bugs. VHDL version only. +-- +-- Revision 1.5 2002/12/26 16:05:47 rherveille +-- Core is now a Multimaster I2C controller. +-- +-- Revision 1.4 2002/11/30 22:24:37 rherveille +-- Cleaned up code +-- +-- Revision 1.3 2002/10/30 18:09:53 rherveille +-- Fixed some reported minor start/stop generation timing issuess. +-- +-- Revision 1.2 2002/06/15 07:37:04 rherveille +-- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment. +-- +-- Revision 1.1 2001/11/05 12:02:33 rherveille +-- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version. +-- Code updated, is now up-to-date to doc. rev.0.4. +-- Added headers. +-- + + +-- +------------------------------------- +-- Bit controller section +------------------------------------ +-- +-- Translate simple commands into SCL/SDA transitions +-- Each command has 5 states, A/B/C/D/idle +-- +-- start: SCL ~~~~~~~~~~~~~~\____ +-- SDA XX/~~~~~~~\______ +-- x | A | B | C | D | i +-- +-- repstart SCL ______/~~~~~~~\___ +-- SDA __/~~~~~~~\______ +-- x | A | B | C | D | i +-- +-- stop SCL _______/~~~~~~~~~~~ +-- SDA ==\___________/~~~~~ +-- x | A | B | C | D | i +-- +--- write SCL ______/~~~~~~~\____ +-- SDA XXX===============XX +-- x | A | B | C | D | i +-- +--- read SCL ______/~~~~~~~\____ +-- SDA XXXXXXX=XXXXXXXXXXX +-- x | A | B | C | D | i +-- + +-- Timing: Normal mode Fast mode +----------------------------------------------------------------- +-- Fscl 100KHz 400KHz +-- Th_scl 4.0us 0.6us High period of SCL +-- Tl_scl 4.7us 1.3us Low period of SCL +-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition +-- Tsu:sto 4.0us 0.6us setup time for a stop conditon +-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +entity i2c_master_bit_ctrl is + port ( + clk : in std_logic; + rst : in std_logic; + nReset : in std_logic; + ena : in std_logic; -- core enable signal + + clk_cnt : in unsigned(15 downto 0); -- clock prescale value + + cmd : in std_logic_vector(3 downto 0); + cmd_ack : out std_logic; -- command completed + busy : out std_logic; -- i2c bus busy + al : out std_logic; -- arbitration lost + + din : in std_logic; + dout : out std_logic; + + -- i2c lines + scl_i : in std_logic; -- i2c clock line input + scl_o : out std_logic; -- i2c clock line output + scl_oen : out std_logic; -- i2c clock line output enable, active low + sda_i : in std_logic; -- i2c data line input + sda_o : out std_logic; -- i2c data line output + sda_oen : out std_logic -- i2c data line output enable, active low + ); +end entity i2c_master_bit_ctrl; + +architecture structural of i2c_master_bit_ctrl is + constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; + constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; + constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; + constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100"; + constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000"; + + type states is (idle, start_a, start_b, start_c, start_d, start_e, + stop_a, stop_b, stop_c, stop_d, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d); + signal c_state : states; + + signal iscl_oen, isda_oen : std_logic; -- internal I2C lines + signal sda_chk : std_logic; -- check SDA status (multi-master arbitration) + signal dscl_oen : std_logic; -- delayed scl_oen signals + signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs + signal clk_en, slave_wait : std_logic; -- clock generation signals + signal ial : std_logic; -- internal arbitration lost signal +-- signal cnt : unsigned(15 downto 0) := clk_cnt; -- clock divider counter (simulation) + signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis) + +begin + -- whenever the slave is not ready it can delay the cycle by pulling SCL low + -- delay scl_oen + process (clk) + begin + if (clk'event and clk = '1') then + dscl_oen <= iscl_oen; + end if; + end process; + slave_wait <= dscl_oen and not sSCL; + + -- generate clk enable signal + gen_clken: process(clk, nReset) + begin + if (nReset = '0') then + cnt <= (others => '0'); + clk_en <= '1'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + cnt <= (others => '0'); + clk_en <= '1'; + elsif ( (cnt = 0) or (ena = '0') ) then + cnt <= clk_cnt; + clk_en <= '1'; + elsif (slave_wait = '1') then + cnt <= cnt; + clk_en <= '0'; + else + cnt <= cnt -1; + clk_en <= '0'; + end if; + end if; + end process gen_clken; + + + -- generate bus status controller + bus_status_ctrl: block + signal dSCL, dSDA : std_logic; -- delayes sSCL and sSDA + signal sta_condition : std_logic; -- start detected + signal sto_condition : std_logic; -- stop detected + signal cmd_stop : std_logic; -- STOP command + signal ibusy : std_logic; -- internal busy signal + begin + -- synchronize SCL and SDA inputs + synch_scl_sda: process(clk, nReset) + begin + if (nReset = '0') then + sSCL <= '1'; + sSDA <= '1'; + + dSCL <= '1'; + dSDA <= '1'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + sSCL <= '1'; + sSDA <= '1'; + + dSCL <= '1'; + dSDA <= '1'; + else + sSCL <= scl_i; + sSDA <= sda_i; + + dSCL <= sSCL; + dSDA <= sSDA; + end if; + end if; + end process synch_SCL_SDA; + + -- detect start condition => detect falling edge on SDA while SCL is high + -- detect stop condition => detect rising edge on SDA while SCL is high + detect_sta_sto: process(clk, nReset) + begin + if (nReset = '0') then + sta_condition <= '0'; + sto_condition <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + sta_condition <= '0'; + sto_condition <= '0'; + else + sta_condition <= (not sSDA and dSDA) and sSCL; + sto_condition <= (sSDA and not dSDA) and sSCL; + end if; + end if; + end process detect_sta_sto; + + -- generate i2c-bus busy signal + gen_busy: process(clk, nReset) + begin + if (nReset = '0') then + ibusy <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + ibusy <= '0'; + else + ibusy <= (sta_condition or ibusy) and not sto_condition; + end if; + end if; + end process gen_busy; + busy <= ibusy; + + + -- generate arbitration lost signal + -- aribitration lost when: + -- 1) master drives SDA high, but the i2c bus is low + -- 2) stop detected while not requested (detect during 'idle' state) + gen_al: process(clk, nReset) + begin + if (nReset = '0') then + cmd_stop <= '0'; + ial <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1') then + cmd_stop <= '0'; + ial <= '0'; + else + if (clk_en = '1') then + if (cmd = I2C_CMD_STOP) then + cmd_stop <= '1'; + else + cmd_stop <= '0'; + end if; + end if; + + if (c_state = idle) then + ial <= (sda_chk and not sSDA and isda_oen); + else + ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop); + end if; + + end if; + end if; + end process gen_al; + al <= ial; + + -- generate dout signal, store dout on rising edge of SCL + gen_dout: process(clk) + begin + if (clk'event and clk = '1') then + if (sSCL = '1' and dSCL = '0') then + dout <= sSDA; + end if; + end if; + end process gen_dout; + end block bus_status_ctrl; + + + -- generate statemachine + nxt_state_decoder : process (clk, nReset, c_state, cmd) + begin + if (nReset = '0') then + c_state <= idle; + cmd_ack <= '0'; + iscl_oen <= '1'; + isda_oen <= '1'; + sda_chk <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1' or ial = '1') then + c_state <= idle; + cmd_ack <= '0'; + iscl_oen <= '1'; + isda_oen <= '1'; + sda_chk <= '0'; + else + cmd_ack <= '0'; -- default no acknowledge + + if (clk_en = '1') then + case (c_state) is + -- idle + when idle => + case cmd is + when I2C_CMD_START => c_state <= start_a; + when I2C_CMD_STOP => c_state <= stop_a; + when I2C_CMD_WRITE => c_state <= wr_a; + when I2C_CMD_READ => c_state <= rd_a; + when others => c_state <= idle; -- NOP command + end case; + + iscl_oen <= iscl_oen; -- keep SCL in same state + isda_oen <= isda_oen; -- keep SDA in same state + sda_chk <= '0'; -- don't check SDA + + -- start + when start_a => + c_state <= start_b; + iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start) + isda_oen <= '1'; -- set SDA high + sda_chk <= '0'; -- don't check SDA + + when start_b => + c_state <= start_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= '1'; -- keep SDA high + sda_chk <= '0'; -- don't check SDA + + when start_c => + c_state <= start_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '0'; -- set SDA low + sda_chk <= '0'; -- don't check SDA + + when start_d => + c_state <= start_e; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + when start_e => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '0'; -- set SCL low + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + -- stop + when stop_a => + c_state <= stop_b; + iscl_oen <= '0'; -- keep SCL low + isda_oen <= '0'; -- set SDA low + sda_chk <= '0'; -- don't check SDA + + when stop_b => + c_state <= stop_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + when stop_c => + c_state <= stop_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '0'; -- keep SDA low + sda_chk <= '0'; -- don't check SDA + + when stop_d => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '1'; -- set SDA high + sda_chk <= '0'; -- don't check SDA + + -- read + when rd_a => + c_state <= rd_b; + iscl_oen <= '0'; -- keep SCL low + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + when rd_b => + c_state <= rd_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + when rd_c => + c_state <= rd_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + when rd_d => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '0'; -- set SCL low + isda_oen <= '1'; -- tri-state SDA + sda_chk <= '0'; -- don't check SDA + + -- write + when wr_a => + c_state <= wr_b; + iscl_oen <= '0'; -- keep SCL low + isda_oen <= din; -- set SDA + sda_chk <= '0'; -- don't check SDA (SCL low) + + when wr_b => + c_state <= wr_c; + iscl_oen <= '1'; -- set SCL high + isda_oen <= din; -- keep SDA + sda_chk <= '1'; -- check SDA + + when wr_c => + c_state <= wr_d; + iscl_oen <= '1'; -- keep SCL high + isda_oen <= din; -- keep SDA + sda_chk <= '1'; -- check SDA + + when wr_d => + c_state <= idle; + cmd_ack <= '1'; -- command completed + iscl_oen <= '0'; -- set SCL low + isda_oen <= din; -- keep SDA + sda_chk <= '0'; -- don't check SDA (SCL low) + + when others => + + end case; + end if; + end if; + end if; + end process nxt_state_decoder; + + + -- assign outputs + scl_o <= '0'; + scl_oen <= iscl_oen; + sda_o <= '0'; + sda_oen <= isda_oen; +end architecture structural; + diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_byte_ctrl.vhd b/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_byte_ctrl.vhd new file mode 100644 index 000000000..bdb2a881e --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_byte_ctrl.vhd @@ -0,0 +1,370 @@ +--------------------------------------------------------------------- +---- ---- +---- WISHBONE revB2 compl. I2C Master Core; byte-controller ---- +---- ---- +---- ---- +---- Author: Richard Herveille ---- +---- richard@asics.ws ---- +---- www.asics.ws ---- +---- ---- +---- Downloaded from: http://www.opencores.org/projects/i2c/ ---- +---- ---- +--------------------------------------------------------------------- +---- ---- +---- Copyright (C) 2000 Richard Herveille ---- +---- richard@asics.ws ---- +---- ---- +---- This source file may be used and distributed without ---- +---- restriction provided that this copyright statement is not ---- +---- removed from the file and that any derivative work contains ---- +---- the original copyright notice and the associated disclaimer.---- +---- ---- +---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ---- +---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ---- +---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ---- +---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ---- +---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ---- +---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---- +---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ---- +---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ---- +---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ---- +---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---- +---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ---- +---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ---- +---- POSSIBILITY OF SUCH DAMAGE. ---- +---- ---- +--------------------------------------------------------------------- + +-- CVS Log +-- +-- $Id: i2c_master_byte_ctrl.vhd,v 1.5 2004/02/18 11:41:48 rherveille Exp $ +-- +-- $Date: 2004/02/18 11:41:48 $ +-- $Revision: 1.5 $ +-- $Author: rherveille $ +-- $Locker: $ +-- $State: Exp $ +-- +-- Change History: +-- $Log: i2c_master_byte_ctrl.vhd,v $ +-- Revision 1.5 2004/02/18 11:41:48 rherveille +-- Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command. +-- +-- Revision 1.4 2003/08/09 07:01:13 rherveille +-- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +-- Fixed a potential bug in the byte controller's host-acknowledge generation. +-- +-- Revision 1.3 2002/12/26 16:05:47 rherveille +-- Core is now a Multimaster I2C controller. +-- +-- Revision 1.2 2002/11/30 22:24:37 rherveille +-- Cleaned up code +-- +-- Revision 1.1 2001/11/05 12:02:33 rherveille +-- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version. +-- Code updated, is now up-to-date to doc. rev.0.4. +-- Added headers. +-- + + + + +-- +------------------------------------------ +-- Byte controller section +------------------------------------------ +-- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +entity i2c_master_byte_ctrl is + port ( + clk : in std_logic; + rst : in std_logic; -- synchronous active high reset (WISHBONE compatible) + nReset : in std_logic; -- asynchornous active low reset (FPGA compatible) + ena : in std_logic; -- core enable signal + + clk_cnt : in unsigned(15 downto 0); -- 4x SCL + + -- input signals + start, + stop, + read, + write, + ack_in : std_logic; + din : in std_logic_vector(7 downto 0); + + -- output signals + cmd_ack : out std_logic; -- command done + ack_out : out std_logic; + i2c_busy : out std_logic; -- arbitration lost + i2c_al : out std_logic; -- i2c bus busy + dout : out std_logic_vector(7 downto 0); + + -- i2c lines + scl_i : in std_logic; -- i2c clock line input + scl_o : out std_logic; -- i2c clock line output + scl_oen : out std_logic; -- i2c clock line output enable, active low + sda_i : in std_logic; -- i2c data line input + sda_o : out std_logic; -- i2c data line output + sda_oen : out std_logic -- i2c data line output enable, active low + ); +end entity i2c_master_byte_ctrl; + +architecture structural of i2c_master_byte_ctrl is + component i2c_master_bit_ctrl is + port ( + clk : in std_logic; + rst : in std_logic; + nReset : in std_logic; + ena : in std_logic; -- core enable signal + + clk_cnt : in unsigned(15 downto 0); -- clock prescale value + + cmd : in std_logic_vector(3 downto 0); + cmd_ack : out std_logic; -- command done + busy : out std_logic; -- i2c bus busy + al : out std_logic; -- arbitration lost + + din : in std_logic; + dout : out std_logic; + + -- i2c lines + scl_i : in std_logic; -- i2c clock line input + scl_o : out std_logic; -- i2c clock line output + scl_oen : out std_logic; -- i2c clock line output enable, active low + sda_i : in std_logic; -- i2c data line input + sda_o : out std_logic; -- i2c data line output + sda_oen : out std_logic -- i2c data line output enable, active low + ); + end component i2c_master_bit_ctrl; + + -- commands for bit_controller block + constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; + constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; + constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; + constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100"; + constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000"; + + -- signals for bit_controller + signal core_cmd : std_logic_vector(3 downto 0); + signal core_ack, core_txd, core_rxd : std_logic; + signal al : std_logic; + + -- signals for shift register + signal sr : std_logic_vector(7 downto 0); -- 8bit shift register + signal shift, ld : std_logic; + + -- signals for state machine + signal go, host_ack : std_logic; + signal dcnt : unsigned(2 downto 0); -- data counter + signal cnt_done : std_logic; + +begin + -- hookup bit_controller + bit_ctrl: i2c_master_bit_ctrl port map( + clk => clk, + rst => rst, + nReset => nReset, + ena => ena, + clk_cnt => clk_cnt, + cmd => core_cmd, + cmd_ack => core_ack, + busy => i2c_busy, + al => al, + din => core_txd, + dout => core_rxd, + scl_i => scl_i, + scl_o => scl_o, + scl_oen => scl_oen, + sda_i => sda_i, + sda_o => sda_o, + sda_oen => sda_oen + ); + i2c_al <= al; + + -- generate host-command-acknowledge + cmd_ack <= host_ack; + + -- generate go-signal + go <= (read or write or stop) and not host_ack; + + -- assign Dout output to shift-register + dout <= sr; + + -- generate shift register + shift_register: process(clk, nReset) + begin + if (nReset = '0') then + sr <= (others => '0'); + elsif (clk'event and clk = '1') then + if (rst = '1') then + sr <= (others => '0'); + elsif (ld = '1') then + sr <= din; + elsif (shift = '1') then + sr <= (sr(6 downto 0) & core_rxd); + end if; + end if; + end process shift_register; + + -- generate data-counter + data_cnt: process(clk, nReset) + begin + if (nReset = '0') then + dcnt <= (others => '0'); + elsif (clk'event and clk = '1') then + if (rst = '1') then + dcnt <= (others => '0'); + elsif (ld = '1') then + dcnt <= (others => '1'); -- load counter with 7 + elsif (shift = '1') then + dcnt <= dcnt -1; + end if; + end if; + end process data_cnt; + + cnt_done <= '1' when (dcnt = 0) else '0'; + + -- + -- state machine + -- + statemachine : block + type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop); + signal c_state : states; + begin + -- + -- command interpreter, translate complex commands into simpler I2C commands + -- + nxt_state_decoder: process(clk, nReset) + begin + if (nReset = '0') then + core_cmd <= I2C_CMD_NOP; + core_txd <= '0'; + shift <= '0'; + ld <= '0'; + host_ack <= '0'; + c_state <= st_idle; + ack_out <= '0'; + elsif (clk'event and clk = '1') then + if (rst = '1' or al = '1') then + core_cmd <= I2C_CMD_NOP; + core_txd <= '0'; + shift <= '0'; + ld <= '0'; + host_ack <= '0'; + c_state <= st_idle; + ack_out <= '0'; + else + -- initialy reset all signal + core_txd <= sr(7); + shift <= '0'; + ld <= '0'; + host_ack <= '0'; + + case c_state is + when st_idle => + if (go = '1') then + if (start = '1') then + c_state <= st_start; + core_cmd <= I2C_CMD_START; + elsif (read = '1') then + c_state <= st_read; + core_cmd <= I2C_CMD_READ; + elsif (write = '1') then + c_state <= st_write; + core_cmd <= I2C_CMD_WRITE; + else -- stop + c_state <= st_stop; + core_cmd <= I2C_CMD_STOP; + end if; + + ld <= '1'; + end if; + + when st_start => + if (core_ack = '1') then + if (read = '1') then + c_state <= st_read; + core_cmd <= I2C_CMD_READ; + else + c_state <= st_write; + core_cmd <= I2C_CMD_WRITE; + end if; + + ld <= '1'; + end if; + + when st_write => + if (core_ack = '1') then + if (cnt_done = '1') then + c_state <= st_ack; + core_cmd <= I2C_CMD_READ; + else + c_state <= st_write; -- stay in same state + core_cmd <= I2C_CMD_WRITE; -- write next bit + shift <= '1'; + end if; + end if; + + when st_read => + if (core_ack = '1') then + if (cnt_done = '1') then + c_state <= st_ack; + core_cmd <= I2C_CMD_WRITE; + else + c_state <= st_read; -- stay in same state + core_cmd <= I2C_CMD_READ; -- read next bit + end if; + + shift <= '1'; + core_txd <= ack_in; + end if; + + when st_ack => + if (core_ack = '1') then + -- check for stop; Should a STOP command be generated ? + if (stop = '1') then + c_state <= st_stop; + core_cmd <= I2C_CMD_STOP; + else + c_state <= st_idle; + core_cmd <= I2C_CMD_NOP; + + -- generate command acknowledge signal + host_ack <= '1'; + end if; + + -- assign ack_out output to core_rxd (contains last received bit) + ack_out <= core_rxd; + + core_txd <= '1'; + else + core_txd <= ack_in; + end if; + + when st_stop => + if (core_ack = '1') then + c_state <= st_idle; + core_cmd <= I2C_CMD_NOP; + + -- generate command acknowledge signal + host_ack <= '1'; + end if; + + when others => -- illegal states + c_state <= st_idle; + core_cmd <= I2C_CMD_NOP; + report ("Byte controller entered illegal state."); + + end case; + + end if; + end if; + end process nxt_state_decoder; + + end block statemachine; + +end architecture structural; + diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_top.vhd b/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_top.vhd new file mode 100644 index 000000000..a2557120f --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_top.vhd @@ -0,0 +1,359 @@ +--------------------------------------------------------------------- +---- ---- +---- WISHBONE revB2 compl. I2C Master Core; top level ---- +---- ---- +---- ---- +---- Author: Richard Herveille ---- +---- richard@asics.ws ---- +---- www.asics.ws ---- +---- ---- +---- Downloaded from: http://www.opencores.org/projects/i2c/ ---- +---- ---- +--------------------------------------------------------------------- +---- ---- +---- Copyright (C) 2000 Richard Herveille ---- +---- richard@asics.ws ---- +---- ---- +---- This source file may be used and distributed without ---- +---- restriction provided that this copyright statement is not ---- +---- removed from the file and that any derivative work contains ---- +---- the original copyright notice and the associated disclaimer.---- +---- ---- +---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ---- +---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ---- +---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ---- +---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ---- +---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ---- +---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---- +---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ---- +---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ---- +---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ---- +---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---- +---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ---- +---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ---- +---- POSSIBILITY OF SUCH DAMAGE. ---- +---- ---- +--------------------------------------------------------------------- + +-- CVS Log +-- +-- $Id: i2c_master_top.vhd,v 1.7 2004/03/14 10:17:03 rherveille Exp $ +-- +-- $Date: 2004/03/14 10:17:03 $ +-- $Revision: 1.7 $ +-- $Author: rherveille $ +-- $Locker: $ +-- $State: Exp $ +-- +-- Change History: +-- $Log: i2c_master_top.vhd,v $ +-- Revision 1.7 2004/03/14 10:17:03 rherveille +-- Fixed simulation issue when writing to CR register +-- +-- Revision 1.6 2003/08/09 07:01:13 rherveille +-- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +-- Fixed a potential bug in the byte controller's host-acknowledge generation. +-- +-- Revision 1.5 2003/02/01 02:03:06 rherveille +-- Fixed a few 'arbitration lost' bugs. VHDL version only. +-- +-- Revision 1.4 2002/12/26 16:05:47 rherveille +-- Core is now a Multimaster I2C controller. +-- +-- Revision 1.3 2002/11/30 22:24:37 rherveille +-- Cleaned up code +-- +-- Revision 1.2 2001/11/10 10:52:44 rherveille +-- Changed PRER reset value from 0x0000 to 0xffff, conform specs. +-- + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +entity i2c_master_top is + generic( + ARST_LVL : std_logic := '0' -- asynchronous reset level + ); + port ( + -- wishbone signals + wb_clk_i : in std_logic; -- master clock input + wb_rst_i : in std_logic := '0'; -- synchronous active high reset + arst_i : in std_logic := not ARST_LVL; -- asynchronous reset + wb_adr_i : in unsigned(2 downto 0); -- lower address bits + wb_dat_i : in std_logic_vector(7 downto 0); -- Databus input + wb_dat_o : out std_logic_vector(7 downto 0); -- Databus output + wb_we_i : in std_logic; -- Write enable input + wb_stb_i : in std_logic; -- Strobe signals / core select signal + wb_cyc_i : in std_logic; -- Valid bus cycle input + wb_ack_o : out std_logic; -- Bus cycle acknowledge output + wb_inta_o : out std_logic; -- interrupt request output signal + + -- i2c lines + scl_pad_i : in std_logic; -- i2c clock line input + scl_pad_o : out std_logic; -- i2c clock line output + scl_padoen_o : out std_logic; -- i2c clock line output enable, active low + sda_pad_i : in std_logic; -- i2c data line input + sda_pad_o : out std_logic; -- i2c data line output + sda_padoen_o : out std_logic -- i2c data line output enable, active low + ); +end entity i2c_master_top; + +architecture structural of i2c_master_top is + component i2c_master_byte_ctrl is + port ( + clk : in std_logic; + rst : in std_logic; -- synchronous active high reset (WISHBONE compatible) + nReset : in std_logic; -- asynchornous active low reset (FPGA compatible) + ena : in std_logic; -- core enable signal + + clk_cnt : in unsigned(15 downto 0); -- 4x SCL + + -- input signals + start, + stop, + read, + write, + ack_in : std_logic; + din : in std_logic_vector(7 downto 0); + + -- output signals + cmd_ack : out std_logic; + ack_out : out std_logic; + i2c_busy : out std_logic; + i2c_al : out std_logic; + dout : out std_logic_vector(7 downto 0); + + -- i2c lines + scl_i : in std_logic; -- i2c clock line input + scl_o : out std_logic; -- i2c clock line output + scl_oen : out std_logic; -- i2c clock line output enable, active low + sda_i : in std_logic; -- i2c data line input + sda_o : out std_logic; -- i2c data line output + sda_oen : out std_logic -- i2c data line output enable, active low + ); + end component i2c_master_byte_ctrl; + + -- registers + signal prer : unsigned(15 downto 0); -- clock prescale register + signal ctr : std_logic_vector(7 downto 0); -- control register + signal txr : std_logic_vector(7 downto 0); -- transmit register + signal rxr : std_logic_vector(7 downto 0); -- receive register + signal cr : std_logic_vector(7 downto 0); -- command register + signal sr : std_logic_vector(7 downto 0); -- status register + + -- internal reset signal + signal rst_i : std_logic; + + -- wishbone write access + signal wb_wacc : std_logic; + + -- internal acknowledge signal + signal iack_o : std_logic; + + -- done signal: command completed, clear command register + signal done : std_logic; + + -- command register signals + signal sta, sto, rd, wr, ack, iack : std_logic; + + signal core_en : std_logic; -- core enable signal + signal ien : std_logic; -- interrupt enable signal + + -- status register signals + signal irxack, rxack : std_logic; -- received aknowledge from slave + signal tip : std_logic; -- transfer in progress + signal irq_flag : std_logic; -- interrupt pending flag + signal i2c_busy : std_logic; -- i2c bus busy (start signal detected) + signal i2c_al, al : std_logic; -- arbitration lost + +begin + -- generate internal reset signal + rst_i <= arst_i xor ARST_LVL; + + -- generate acknowledge output signal + gen_ack_o : process(wb_clk_i) + begin + if (wb_clk_i'event and wb_clk_i = '1') then + iack_o <= wb_cyc_i and wb_stb_i and not iack_o; -- because timing is always honored + end if; + end process gen_ack_o; + wb_ack_o <= iack_o; + + + -- generate wishbone write access signal + wb_wacc <= wb_cyc_i and wb_stb_i and wb_we_i; + + -- assign wb_dat_o + assign_dato : process(wb_clk_i) + begin + if (wb_clk_i'event and wb_clk_i = '1') then + case wb_adr_i is + when "000" => wb_dat_o <= std_logic_vector(prer( 7 downto 0)); + when "001" => wb_dat_o <= std_logic_vector(prer(15 downto 8)); + when "010" => wb_dat_o <= ctr; + when "011" => wb_dat_o <= rxr; -- write is transmit register TxR + when "100" => wb_dat_o <= sr; -- write is command register CR + + -- Debugging registers: + -- These registers are not documented. + -- Functionality could change in future releases + when "101" => wb_dat_o <= txr; + when "110" => wb_dat_o <= cr; + when "111" => wb_dat_o <= (others => '0'); + when others => wb_dat_o <= (others => 'X'); -- for simulation only + end case; + end if; + end process assign_dato; + + + -- generate registers (CR, SR see below) + gen_regs: process(rst_i, wb_clk_i) + begin + if (rst_i = '0') then + prer <= (others => '1'); + ctr <= (others => '0'); + txr <= (others => '0'); + elsif (wb_clk_i'event and wb_clk_i = '1') then + if (wb_rst_i = '1') then + prer <= (others => '1'); + ctr <= (others => '0'); + txr <= (others => '0'); + elsif (wb_wacc = '1') then + case wb_adr_i is + when "000" => prer( 7 downto 0) <= unsigned(wb_dat_i); + when "001" => prer(15 downto 8) <= unsigned(wb_dat_i); + when "010" => ctr <= wb_dat_i; + when "011" => txr <= wb_dat_i; + when "100" => null; --write to CR, avoid executing the others clause + + -- illegal cases, for simulation only + when others => + report ("Illegal write address, setting all registers to unknown."); + prer <= (others => 'X'); + ctr <= (others => 'X'); + txr <= (others => 'X'); + end case; + end if; + end if; + end process gen_regs; + + + -- generate command register + gen_cr: process(rst_i, wb_clk_i) + begin + if (rst_i = '0') then + cr <= (others => '0'); + elsif (wb_clk_i'event and wb_clk_i = '1') then + if (wb_rst_i = '1') then + cr <= (others => '0'); + elsif (wb_wacc = '1') then + if ( (core_en = '1') and (wb_adr_i = 4) ) then + -- only take new commands when i2c core enabled + -- pending commands are finished + cr <= wb_dat_i; + end if; + else + if (done = '1' or i2c_al = '1') then + cr(7 downto 4) <= (others => '0'); -- clear command bits when command done or arbitration lost + end if; + + cr(2 downto 1) <= (others => '0'); -- reserved bits, always '0' + cr(0) <= '0'; -- clear IRQ_ACK bit + end if; + end if; + end process gen_cr; + + -- decode command register + sta <= cr(7); + sto <= cr(6); + rd <= cr(5); + wr <= cr(4); + ack <= cr(3); + iack <= cr(0); + + -- decode control register + core_en <= ctr(7); + ien <= ctr(6); + + -- hookup byte controller block + byte_ctrl: i2c_master_byte_ctrl port map ( + clk => wb_clk_i, + rst => wb_rst_i, + nReset => rst_i, + ena => core_en, + clk_cnt => prer, + start => sta, + stop => sto, + read => rd, + write => wr, + ack_in => ack, + i2c_busy => i2c_busy, + i2c_al => i2c_al, + din => txr, + cmd_ack => done, + ack_out => irxack, + dout => rxr, + scl_i => scl_pad_i, + scl_o => scl_pad_o, + scl_oen => scl_padoen_o, + sda_i => sda_pad_i, + sda_o => sda_pad_o, + sda_oen => sda_padoen_o + ); + + + -- status register block + interrupt request signal + st_irq_block : block + begin + -- generate status register bits + gen_sr_bits: process (wb_clk_i, rst_i) + begin + if (rst_i = '0') then + al <= '0'; + rxack <= '0'; + tip <= '0'; + irq_flag <= '0'; + elsif (wb_clk_i'event and wb_clk_i = '1') then + if (wb_rst_i = '1') then + al <= '0'; + rxack <= '0'; + tip <= '0'; + irq_flag <= '0'; + else + al <= i2c_al or (al and not sta); + rxack <= irxack; + tip <= (rd or wr); + + -- interrupt request flag is always generated + irq_flag <= (done or i2c_al or irq_flag) and not iack; + end if; + end if; + end process gen_sr_bits; + + -- generate interrupt request signals + gen_irq: process (wb_clk_i, rst_i) + begin + if (rst_i = '0') then + wb_inta_o <= '0'; + elsif (wb_clk_i'event and wb_clk_i = '1') then + if (wb_rst_i = '1') then + wb_inta_o <= '0'; + else + -- interrupt signal is only generated when IEN (interrupt enable bit) is set + wb_inta_o <= irq_flag and ien; + end if; + end if; + end process gen_irq; + + -- assign status register bits + sr(7) <= rxack; + sr(6) <= i2c_busy; + sr(5) <= al; + sr(4 downto 2) <= (others => '0'); -- reserved + sr(1) <= tip; + sr(0) <= irq_flag; + end block; + +end architecture structural; diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/readme b/fpga/usrp2/opencores/i2c/rtl/vhdl/readme new file mode 100644 index 000000000..0d049f736 --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/readme @@ -0,0 +1,25 @@ + + +-- This code is provided for free and may be used and -- +-- distributed without restriction provided that the -- +-- copyright statement is not removed from the file and -- +-- that any derivative work contains the original -- +-- copyright notice and the associated disclaimer. -- + +-- Comments and suggestions are always welcome -- + +The i2c_master core consists of three files: + +- i2c_master_top -- top level +- i2c_master_byte_ctrl -- byte controller +- i2c_master_bit_ctrl -- bit controller + +VHDL needs to be compiled in order. The files are listed +above in descending order. + +I2C.VHD and tst_ds1621.vhd are not supported anymore. +They remain mostly for historical purposes, altough they +might prove usefull. + +Richard Herveille +rherveille@opencores.org diff --git a/fpga/usrp2/opencores/i2c/rtl/vhdl/tst_ds1621.vhd b/fpga/usrp2/opencores/i2c/rtl/vhdl/tst_ds1621.vhd new file mode 100644 index 000000000..ccf50460c --- /dev/null +++ b/fpga/usrp2/opencores/i2c/rtl/vhdl/tst_ds1621.vhd @@ -0,0 +1,283 @@ +-- +-- +-- State machine for reading data from Dallas 1621 +-- +-- Testsystem for i2c controller +-- +-- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; + +use work.i2c.all; + +entity DS1621_interface is + port ( + clk : in std_logic; + nReset : in std_logic; + + Dout : out std_logic_vector(7 downto 0); -- data read from ds1621 + + error : out std_logic; -- no correct ack received + + SCL : inout std_logic; + SDA : inout std_logic + ); +end entity DS1621_interface; + +architecture structural of DS1621_interface is + constant SLAVE_ADDR : std_logic_vector(6 downto 0) := "1001000"; + constant CLK_CNT : unsigned(7 downto 0) := conv_unsigned(20, 8); + + signal cmd_ack : std_logic; + signal D : std_logic_vector(7 downto 0); + signal lack, store_dout : std_logic; + + signal start, read, write, ack, stop : std_logic; + signal i2c_dout : std_logic_vector(7 downto 0); + +begin + -- hookup I2C controller + u1: simple_i2c port map (clk => clk, ena => '1', clk_cnt => clk_cnt, nReset => nReset, + read => read, write => write, start => start, stop => stop, ack_in => ack, cmd_ack => cmd_ack, + Din => D, Dout => i2c_dout, ack_out => lack, SCL => SCL, SDA => SDA); + + init_statemachine : block + type states is (i1, i2, i3, i4, i5, t1, t2, t3, t4, t5); + signal state : states; + begin + nxt_state_decoder: process(clk, nReset, state) + variable nxt_state : states; + variable iD : std_logic_vector(7 downto 0); + variable ierr : std_logic; + variable istart, iread, iwrite, iack, istop : std_logic; + variable istore_dout : std_logic; + begin + nxt_state := state; + ierr := '0'; + istore_dout := '0'; + + istart := start; + iread := read; + iwrite := write; + iack := ack; + istop := stop; + iD := D; + + case (state) is + -- init DS1621 + -- 1) send start condition + -- 2) send slave address + write + -- 3) check ack + -- 4) send "access config" command (0xAC) + -- 5) check ack + -- 6) send config register data (0x00) + -- 7) check ack + -- 8) send stop condition + -- 9) send start condition + -- 10) send slave address + write + -- 11) check ack + -- 12) send "start conversion" command (0xEE) + -- 13) check ack + -- 14) send stop condition + + when i1 => -- send start condition, sent slave address + write + nxt_state := i2; + istart := '1'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '0'; + iD := (slave_addr & '0'); -- write to slave (R/W = '0') + + when i2 => -- send "access config" command + if (cmd_ack = '1') then + nxt_state := i3; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received from last command, expected ACK + end if; + + istart := '0'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '0'; + iD := x"AC"; + end if; + + when i3 => -- send config register data, sent stop condition + if (cmd_ack = '1') then + nxt_state := i4; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received from last command, expected ACK + end if; + + istart := '0'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '1'; + iD := x"00"; + end if; + + when i4 => -- send start condition, sent slave address + write + if (cmd_ack = '1') then + nxt_state := i5; + + istart := '1'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '0'; + iD := (slave_addr & '0'); -- write to slave (R/W = '0') + end if; + + when i5 => -- send "start conversion" command + stop condition + if (cmd_ack = '1') then + nxt_state := t1; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received from last command, expected ACK + end if; + + istart := '0'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '1'; + iD := x"EE"; + end if; + -- read temperature + -- 1) sent start condition + -- 2) sent slave address + write + -- 3) check ack + -- 4) sent "read temperature" command (0xAA) + -- 5) check ack + -- 6) sent start condition + -- 7) sent slave address + read + -- 8) check ack + -- 9) read msb + -- 10) send ack + -- 11) read lsb + -- 12) send nack + -- 13) send stop condition + + when t1 => -- send start condition, sent slave address + write + if (cmd_ack = '1') then + nxt_state := t2; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received from last command, expected ACK + end if; + + istart := '1'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '0'; + iD := (slave_addr & '0'); -- write to slave (R/W = '0') + end if; + + when t2 => -- send read temperature command + if (cmd_ack = '1') then + nxt_state := t3; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received from last command, expected ACK + end if; + + istart := '0'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '0'; + iD := x"AA"; + end if; + + when t3 => -- send (repeated) start condition, send slave address + read + if (cmd_ack = '1') then + nxt_state := t4; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received, expected ACK + end if; + + istart := '1'; + iread := '0'; + iwrite := '1'; + iack := '0'; + istop := '0'; + iD := (slave_addr & '1'); -- read from slave (R/W = '1') + end if; + + when t4 => -- read MSB (hi-byte), send acknowledge + if (cmd_ack = '1') then + nxt_state := t5; + -- check aknowledge bit + if (lack = '1') then + ierr := '1'; -- no acknowledge received from last command, expected ACK + end if; + + istart := '0'; + iread := '1'; + iwrite := '0'; + iack := '0'; --ACK + istop := '0'; + end if; + + when t5 => -- read LSB (lo-byte), send acknowledge, sent stop + if (cmd_ack = '1') then + nxt_state := t1; + + istart := '0'; + iread := '1'; + iwrite := '0'; + iack := '1'; --NACK + istop := '1'; + + istore_dout := '1'; + end if; + end case; + + -- genregs + if (nReset = '0') then + state <= i1; + error <= '0'; + store_dout <= '0'; + + start <= '0'; + read <= '0'; + write <= '0'; + ack <= '0'; + stop <= '0'; + D <= (others => '0'); + elsif (clk'event and clk = '1') then + state <= nxt_state; + error <= ierr; + store_dout <= istore_dout; + + start <= istart; + read <= iread; + write <= iwrite; + ack <= iack; + stop <= istop; + D <= iD; + end if; + end process nxt_state_decoder; + end block init_statemachine; + + -- store temp + gen_dout : process(clk) + begin + if (clk'event and clk = '1') then + if (store_dout = '1') then + Dout <= i2c_dout; + end if; + end if; + end process gen_dout; + +end architecture structural; + + |