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

📄 i2c_core.vhd

📁 i2c源码vhdl语言编写
💻 VHD
字号:
-- 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 <= '0'; --'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;--每个clk_en进行状态跳转
				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 + -