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

📄 simple_i2c.vhd

📁 i2c源码vhdl语言编写
💻 VHD
字号:
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 : 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  --load
				sr <= din;
			elsif (shift = '1') then --shift
				sr <= (sr(6 downto 0) & core_rxd);--i2c读出的信号放在后面
			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   --go 信号是一个开始信号,起到起始作用
						if (start = '1') then
							nxt_state := st_start;	
							icore_cmd := CMD_START;
						elsif (read = '1') then --Q:不是必须进入start么?为什么可以不呢?
							nxt_state := st_read;
							icore_cmd := CMD_READ;
							idcnt := "111";
					    else
							nxt_state := st_write;
							icore_cmd := CMD_WRITE;
							idcnt := "111";
							iload := '1';--write状态下进行数据导入
						end if;
					end if;

				when st_start =>        --Q:如果不进入start直接进入read or write呢?
					if (core_ack = '1') then--说明start状态完成了
						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);--要写入的数据  --note
						if (dcnt = 0) then  --写够8个时
							nxt_state := st_ack;
							icore_cmd := CMD_READ;--等待读ack?
						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;--写ack?
							icore_txd := ack_in;
						end if;
					end if;			

				when st_ack =>   --在此状态下可能写ack也可能读ack
					if (core_ack = '1') then
						-- generate command acknowledge signal
						ihost_ack := '1';     --说明ack处理结束,有可能读或写

						-- Perform an additional shift, needed for 'read' (store last received bit in shift register)
						ishift := '1';   --这样吧最后1bit的core_rxd读入sr?

						--在写入状态,应该读ack信号时,检查是否为低,表示有正确的ack信号
						--if(icore_cmd=CMD_READ and core_txd='0') then	--modify
							-- 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;
						--elsif(icore_cmd=CMD_READ and core_txd='1') then
						--    nxt_state := st_stop;
						--	icore_cmd := CMD_STOP;
						--else 
						--    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;						
					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;


⌨️ 快捷键说明

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