📄 simple_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;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); core_txd<=icore_txd;--放在时钟同步里面就慢一个时钟周期。 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; -- test<=core_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--
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -