diff options
author | Josh Blum <josh@joshknows.com> | 2010-04-16 09:42:46 +0000 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-04-16 09:42:46 +0000 |
commit | 835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25 (patch) | |
tree | 4fe48bdaf92311deedfbe1a5e77dd209468a2d7d /fpga/usrp2/opencores/i2c/rtl/vhdl | |
parent | f1838b9284a124fcfb5996eaf1647a69b4473278 (diff) | |
parent | 067491b58676cbdaa754334949a8ffc2daf32979 (diff) | |
download | uhd-835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25.tar.gz uhd-835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25.tar.bz2 uhd-835cb56ef820a69e1e6e0ccde7c5a0e78ca5ad25.zip |
Merge branch 'master' of git@ettus.sourcerepo.com:ettus/uhdpriv into usrp_e
Conflicts:
.gitignore
Diffstat (limited to 'fpga/usrp2/opencores/i2c/rtl/vhdl')
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Entries | 7 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Repository | 1 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Root | 1 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/CVS/Template | 0 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/I2C.VHD | 620 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_bit_ctrl.vhd | 495 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_byte_ctrl.vhd | 370 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/i2c_master_top.vhd | 359 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/readme | 25 | ||||
-rw-r--r-- | fpga/usrp2/opencores/i2c/rtl/vhdl/tst_ds1621.vhd | 283 |
10 files changed, 2161 insertions, 0 deletions
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; + + |