📄 i2c_core.vhd
字号:
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; -- state<=nxt_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 '1'; -- since SCL is externally pulled-up convert a '1' to a 'Z'(tri-state) SDA <= '0' when (SDAo = '0') else '1'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state) -- test<=clk_en;-- SCL <= SCLo;-- SDA <= SDAo;end architecture structural;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -