⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.vhd

📁 来自opencore网站的I2C总线模块
💻 VHD
字号:
---- 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -