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; + +  | 
