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

📄 i2c_eeprom.vhd

📁 模拟I2C EEPROM的VHDL代码。如常见的24c02等。
💻 VHD
字号:
--==========================================================================================================--
--                                                                                                          --
--                         Copyright (c) 2002 by IBM , Inc.   All rights reserved.                          --
--                                                                                                          --
--                      Martin Neumann mneumann@de.ibm.com - IBM EF Boeblingen GERMANY                      --
--                                                                                                          --
--==========================================================================================================--
--  File name: I2C_EEPROM.vhd                                                                               --
--  Designer : M. Neumann                                                                                   --
--  Description:  Simulation of a series 24Cxx I2C EEPROM (24C01, 24C02, 24C04, 24C08 and 24C16)            --
--                                                                                                          --
--==========================================================================================================--

library IEEE;
  use IEEE.std_logic_1164.all;
  use IEEE.std_logic_unsigned.all;   -- function conv_integer

entity I2C_EEPROM is
 generic (device : string(1 to 5) := "24C16");  --select from 24C16, 24C08, 24C04, 24C02 and 24C01
 port (
  STRETCH            : IN    time := 1 ns;      --pull SCL low for this time-value;
  E0                 : IN    std_logic := 'L';  --leave unconnected for 24C16, 24C08, 24C04
  E1                 : IN    std_logic := 'L';  --leave unconnected for 24C16, 24C08
  E2                 : IN    std_logic := 'L';  --leave unconnected for 24C16
  WC                 : IN    std_logic := 'L';  --tie high to disable write mode
  SCL                : INOUT std_logic;
  SDA                : INOUT std_logic
);
END I2C_EEPROM;


--==========================================================================================================--

architecture SIM of I2C_EEPROM is

   type      memory_array  is array(0 to 2047) of std_logic_vector(7 downto 0);
   type      I2C_STATE     is (IDLE, ID_CODE, ID_ACK, WR_ADDR, AR_ACK, WR_DATA, WR_ACK, RD_DATA, RD_ACK);

   function addr_bits(name : STRING(1 to 5)) return positive is
   begin
     if    device="24C16" then return 11;
     elsif device="24C08" then return 10;
     elsif device="24C04" then return  9;
     elsif device="24C02" then return  8;
     else                      return  7;
     end if;
   end addr_bits;


   constant  ADDR_MSB      : positive := addr_bits(device) -1;
   signal    ADDR_WORD     : std_logic_vector(10 downto 0);
   signal    BIT_PTR       : natural;
   signal    MEM_ADDR      : natural;
   signal    MEM_DATA      : memory_array;
   signal    THIS_STATE    : I2C_STATE;
   signal    NEXT_STATE    : I2C_STATE;
   signal    SCL_IN        : std_logic;
   signal    SCL_OLD       : std_logic;
   signal    SCL_OUT       : std_logic;
   signal    SDA_IN        : std_logic;
   signal    SDA_OUT       : std_logic;
   signal    START_DET     : std_logic;
   signal    STOP_DET      : std_logic;
   signal    DEVICE_SEL    : std_logic;
   signal    RD_MODE       : std_logic;
   signal    WRITE_EN      : std_logic;
   signal    RECV_BYTE     : std_logic_vector(7 downto 0);
   signal    XMIT_BYTE     : std_logic_vector(7 downto 0);

begin

  SCL_IN <= '1' when SCL='1' or SCL='H' else
            '0' when SCL='0' else 'X';

  SDA_IN <= '1' when SDA='1' or SDA='H' else
            '0' when SDa='0' else 'X';

  SCL_OLD <= SCL_IN after 10 ns;

  p_START_DET :
  process (SDA_IN, SCL_IN)
  begin
    if SDA_IN'event and SDA_IN ='0' and SCL_IN ='1' and SCL_OLD ='1' then
      START_DET <= '1';
    elsif SCL_IN'event and SCL_IN ='1' and THIS_STATE=ID_CODE then
      START_DET <='0';
    end if;
  end process;

  p_STOP_DET :
  process (SDA_IN, THIS_STATE)
  begin
    if SDA_IN'event and SDA_IN ='1' and SCL_IN ='1' and SCL_OLD ='1' then
      STOP_DET  <= '1';
    elsif THIS_STATE =IDLE then
      STOP_DET  <='0' after 30 ns;
    end if;
  end process;

  p_THIS_STATE :
  process (STOP_DET, SCL_IN)
  begin
    if (STOP_DET ='1') then
      THIS_STATE <= IDLE;
    elsif SCL_IN'event and SCL_IN='0' then
      THIS_STATE <= NEXT_STATE;
    end if;
  end process;

  p_NEXT_STATE :
  process(START_DET, THIS_STATE, BIT_PTR, SDA_IN, DEVICE_SEL, RD_MODE)
  begin
    if START_DET ='1'                         then NEXT_STATE <= ID_CODE;
    else
      case THIS_STATE is
        when ID_CODE => if    (BIT_PTR > 0)   then NEXT_STATE <= ID_CODE;
                        else                       NEXT_STATE <= ID_ACK;
                        end if;
        when ID_ACK  => if    (DEVICE_SEL='1'
                           and RD_MODE='1')   then NEXT_STATE <= RD_DATA;
                        elsif (DEVICE_SEL='1'
                           and RD_MODE='0')   then NEXT_STATE <= WR_ADDR;
                        else                       NEXT_STATE <= IDLE;
                        end if;
        when WR_ADDR => if    (BIT_PTR > 0)   then NEXT_STATE <= WR_ADDR;
                        else                       NEXT_STATE <= AR_ACK;
                        end if;
        when AR_ACK  =>                            NEXT_STATE <= WR_DATA;
        when WR_DATA => if    (BIT_PTR > 0)   then NEXT_STATE <= WR_DATA;
                        else                       NEXT_STATE <= WR_ACK;
                        end if;
        when WR_ACK  =>                            NEXT_STATE <= WR_DATA;
        when RD_DATA => if    (BIT_PTR > 0)   then NEXT_STATE <= RD_DATA;
                        else                       NEXT_STATE <= RD_ACK;
                        end if;
        when RD_ACK  => if    (SDA_IN ='0')   then NEXT_STATE <= RD_DATA;
                        else                       NEXT_STATE <= IDLE;
                        end if;
        when others  =>                            NEXT_STATE <= IDLE;
      end case;
    end if;
  end process;

  RECV_BYTE(0) <= SDA_IN;

  p_RECV_BYTE :
  process begin wait until SCL_IN'event and SCL_IN ='0';
    RECV_BYTE(7 downto 1) <= RECV_BYTE(6 downto 0);
  end process;

  p_RD_MODE :
  process begin wait until SCL_IN'event and SCL_IN ='0';
    if NEXT_STATE=ID_ACK then
      RD_MODE <= RECV_BYTE(0);
    end if;
  end process;

  p_DEVICE_SEL :
  process begin wait until SCL_IN'event and SCL_IN ='0';
    if NEXT_STATE=ID_ACK then
      if (device="24C16" and RECV_BYTE(7 downto 4)="1010")
      or (device="24C08" and RECV_BYTE(7 downto 4)="1010" and E2      =RECV_BYTE(3))
      or (device="24C04" and RECV_BYTE(7 downto 4)="1010" and E2&E1   =RECV_BYTE(3 downto 2))
      or (device="24C02" and RECV_BYTE(7 downto 4)="1010" and E2&E1&E0=RECV_BYTE(3 downto 1))
      or (device="24C01" and RECV_BYTE(7 downto 4)="1010" and E2&E1&E0=RECV_BYTE(3 downto 1)) then
        DEVICE_SEL <= '1';
      end if;
    else
      DEVICE_SEL <= '0';
    end if;
  end process;

  WRITE_EN <= '1' when WC='0' or WC='L' else '0';

  with THIS_STATE select
    SDA_OUT <= XMIT_BYTE(BIT_PTR) after 30 ns when RD_DATA,
               not DEVICE_SEL     after 30 ns when ID_ACK,
               '0'                after 30 ns when AR_ACK,
               not WRITE_EN       after 30 ns when WR_ACK,
               'Z'                after 30 ns when others;

  SDA <= SDA_OUT;

  p_SCL_OUT :
  process begin
  SCL_OUT <= 'Z';
  wait until SCL_IN'event and SCL_IN ='0';
    SCL_OUT <= '0';
    wait for STRETCH;
    SCL_OUT <= 'Z';
  end process;

  SCL <= SCL_OUT;

  p_BIT_PTR :
  process(SCL_IN, THIS_STATE, START_DET)
  begin
    if START_DET ='1' then
      BIT_PTR <= 7;
    elsif SCL_IN'event and SCL_IN ='0' then
      if    NEXT_STATE=ID_ACK  or NEXT_STATE=AR_ACK  or NEXT_STATE=WR_ACK  or NEXT_STATE=RD_ACK  then
        BIT_PTR <= 8;
      elsif NEXT_STATE=ID_CODE or NEXT_STATE=WR_ADDR or NEXT_STATE=WR_DATA or NEXT_STATE=RD_DATA then
        BIT_PTR <= BIT_PTR -1;
      end if;
    end if;
  end process;

  ADDR_WORD(7 downto 0) <= RECV_BYTE;

  p_MEM_ADDR :
  process
   constant ADDR_MAX : positive := 2**(ADDR_MSB+1) -1;
  begin
    wait until SCL_IN'event and SCL_IN='0';
    if NEXT_STATE = ID_ACK then
      ADDR_WORD(10 downto 8) <= RECV_BYTE(3 downto 1);
    end if;
    if NEXT_STATE = AR_ACK then
      MEM_ADDR <= conv_integer(ADDR_WORD(ADDR_MSB downto 0));
    elsif (NEXT_STATE=RD_ACK) then
      if MEM_ADDR = ADDR_MAX then
        MEM_ADDR <= 0;
      else
        MEM_ADDR <= MEM_ADDR +1;
      end if;
    elsif (THIS_STATE=WR_ACK and SDA_IN='0') then        -- update Wr-pointer after writing completed
      if MEM_ADDR MOD 16 = 15 then      -- Page max !
        MEM_ADDR <= MEM_ADDR -15;
      else
        MEM_ADDR <= MEM_ADDR +1;
      end if;
    end if;
  end process;

  p_MEM_WR :
  process begin wait until SCL_IN'event and SCL_IN='0';
    if  NEXT_STATE=WR_ACK and WRITE_EN='1' then
      MEM_DATA(MEM_ADDR) <= RECV_BYTE;
    end if;
  end process;

  XMIT_BYTE <= MEM_DATA(MEM_ADDR);

--==========================================================================================================--

end SIM;

   configuration CFG_I2C_EEPROM of I2C_EEPROM is
    for SIM
    end for;
   end CFG_I2C_EEPROM;
--========================================= END OF I2C_EEPROM ===============================================--

⌨️ 快捷键说明

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