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

📄 i2c.vhd

📁 这是一个I2C接口的VHDL实现模块
💻 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 : 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 + -