📄 eeprom_interface.vhd
字号:
-- i2c.vhd
--
-- This file implements an I2C Master interface that will read data
-- from an external NVM (AT24C02A) at power-up to initialize a 256x8
-- internal SRAM block. When external logic signals for an NVM write
-- access, the block reads data from the external source and writes
-- it to the specified I2C address.
------------------------------------------------------------------------
--
-- Copyright 2004 Actel corporation
--
------------------------------------------------------------------------
--
-- Version 1.2 06/04/04 J.Vorgert - working file
--
------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity i2c is
port(reset_n : in std_logic; -- active low reset
clk : in std_logic; -- processor clock
init : out std_logic; -- high during init
ienb : out std_logic; -- low to enable write
iaddr : out std_logic_vector(7 downto 0); -- init address
idata : out std_logic_vector(7 downto 0); -- init data
iclk : out std_logic; -- init clock
updt : in std_logic; -- high to trigger mirror image update
uenb : out std_logic; -- low to enable fifo
uaddr : in std_logic_vector(7 downto 0); -- write address
udata : in std_logic_vector(7 downto 0); -- write data
sdi : in std_logic; -- serial input
sdo : out std_logic; -- active low open-drain drive enable - data
sck : out std_logic -- active low open-drain drive enable - clock
);
end i2c;
architecture rtl of i2c is
signal btck : std_logic;
signal sten : std_logic;
signal cstate : std_logic_vector(3 downto 0);
signal bcnt : std_logic_vector(3 downto 0);
signal ccnt : std_logic_vector(7 downto 0);
signal dly : std_logic;
signal d2i, d2 : std_logic;
signal nki : std_logic;
signal nack : std_logic;
signal wri : std_logic;
signal rdi : std_logic;
signal byte : std_logic_vector(8 downto 0);
signal sdata : std_logic_vector(8 downto 0);
signal ld_byte : std_logic;
signal stsp : std_logic;
signal ctl_val : std_logic;
begin
-- Need to generate divide by 2 to use at the bit clock so that
-- we can generate start and stop bits and space everything right.
c1:process(reset_n, clk)
begin
if(reset_n = '0') then
btck <= '0';
elsif(clk'event AND clk = '1') then
btck <= NOT(btck) after 1 ns;
end if;
end process;
-- INIT is set at power-up and cleared when the state machine
-- reaches state 0101.
wp:process(reset_n, clk)
begin
if(reset_n = '0') then
init <= '1';
elsif(clk'event AND clk = '1') then
if(cstate = "0101") then
init <= '0' after 1 ns;
end if;
end if;
end process;
-- This state machine is set-up to read/write data to an AT24C02A
-- serial Flash memory
--
-- At power-up, the INIT bit is set, and the state machine executes
-- a 'sequencial read' operation starting at address 0x000 and
-- procedding until all 256 bytes have been read and forwarded into
-- the internal memory block. The state machine then sends a
-- stop bit to the Flash and clears the INIT control bit.
--
-- The state machine then waits for updt to be set.
-- When the updt bit is set, the interface asserts u_enb low on a
-- falling-edge of clk and addr/data is latched on the next falling edge
-- (rd_clk should be on the rising-edge). The state machine writes
-- data to the external FLASH memory one byte at a time whenever
-- updt is asserted high. If the FIFO remains 'not empty' then this
-- block will poll the NVM until it is ready, and then proceed with
-- a write cycle for the next byte.
--
-- State Machine:
--
-- 0000 - reset state: generate a start bit and load 0xA0 command
-- 0001 - send byte: then load 0x00 address
-- 0010 - send byte: generate a start bit and load 0xA1 command
-- 0011 - send byte: clear byte count
-- 0100 - receive byte: if cnt /= FF: ack, cnt++, goto 0004 else: nack
-- 0101 - stop: assert stop bit and loop until updt = 1 - then
-- generate a start bit and load A0
-- 0110 - send byte: send byte - if nack - goto 0101, else load Address
-- 0111 - send byte: send data byte, load data
-- 1000 - send byte: goto 0101
--
-- In practice, the state machine is just a counter that starts at zero
-- and counts up, then jumps back to 101 and counts up again,
-- returning to zero only when reset_n is asserted low.
sten <= '1' when ( bcnt(3) = '1' AND
(cstate(2) /= '1' OR cstate(2 downto 1) = "11" OR
cstate(3) = '1' OR (cstate = "0100" AND ccnt = "11111111") OR
(cstate = "0101" AND updt = '1'))) else '0';
s1:process(reset_n, clk)
begin
if(reset_n = '0') then
cstate <= "0000";
elsif(clk'event and clk = '0') then
if(sten = '1' AND btck = '0') then
if(cstate < "0101" AND nack = '1') then
cstate <= "0000" after 1 ns;
elsif(cstate(3) = '1' OR nack = '1') then
cstate <= "0101" after 1 ns;
else
cstate <= cstate + '1' after 1 ns;
end if;
end if;
end if;
end process;
-- The bit counter (bcnt) is cleared at the state transition
-- and during the first cycle of state "0011" (for start bit).
-- incremented on the falling-edge of clk when btck is low.
bc:process(reset_n, clk)
begin
if(reset_n = '0') then
bcnt <= (OTHERS => '0');
dly <= '0';
elsif(clk'event AND clk = '0') then
if(btck = '0') then
if(bcnt(3) = '1' AND cstate = "0010") then
dly <= '1' after 1 ns;
else
dly <= '0';
end if;
if(bcnt(3) = '1' OR (cstate = "0011" AND dly = '1')) then
bcnt <= (OTHERS => '0') after 1 ns;
else
bcnt <= bcnt + '1' after 1 ns;
end if;
end if;
end if;
end process;
-- The byte counter (ccnt) is cleared in state 0011.
-- It is incremented during the ACK bit after each
-- byte transfer in state 0100 to count 0x00-0xFF bytes
-- as they are read from the NVM. ccnt is used both as
-- a control signal and as the iaddr output.
d2i <= '1' when (btck = '1' AND bcnt(3) = '1' AND cstate = "0100")
else '0';
cc:process(reset_n, clk)
begin
if(reset_n = '0') then
ccnt <= (OTHERS => '0');
d2 <= '0';
elsif(clk'event AND clk = '0') then
d2 <= d2i after 1 ns;
if(cstate = "0011") then
ccnt <= (OTHERS => '0') after 1 ns;
elsif(d2 = '1') then
ccnt <= ccnt + '1' after 1 ns;
end if;
end if;
end process;
-- the following logic checks the ACK bit for all states except
-- states "0100" and "0101" and asserts NACK if the data pin is
-- high during the 9th bit of any transfer. This is registered
-- so that the value is present during state changes.
nki <= '1' when (bcnt(3) = '1' AND cstate /= "0100" AND cstate /= "0101"AND sdi = '1')
else '0';
p1:process(reset_n, clk)
begin
if(reset_n = '0') then
nack <= '0';
elsif(clk'event AND clk = '1') then
if(btck = '1') then
nack <= nki after 1 ns;
end if;
end if;
end process;
-- Write enables are cleared to 1 at power-up and are asserted low during
-- ACK in state 0100.
wri <= '0' when (cstate = "0100" AND bcnt(3) = '1' AND btck = '1') else '1';
P2:process(reset_n, clk)
begin
if(reset_n = '0') then
ienb <= '1';
elsif(clk'event AND clk = '0') then
ienb <= wri after 1 ns;
end if;
end process;
iaddr <= ccnt(7 downto 0); -- use byte count as address
idata <= sdata(8 downto 1); -- account for ACK bit
iclk <= NOT(btck); -- invert BTCK and use the rising-edge of this
-- signal as the write clock into internal SRAM
-- u_enb is cleared to 1 at power-up and is asserted low in state 0111
-- while bcnt=7 and btck=1. It is clocked on the falling-edge
-- of clk so rd_clk should occur on the rising-edge.
rdi <= '0' when (cstate = "0111" AND bcnt = "0111" AND btck = '1') else '1';
P3:process(reset_n, clk)
begin
if(reset_n = '0') then
uenb <= '1';
elsif(clk'event AND clk = '0') then
uenb <= rdi after 1 ns;
end if;
end process;
-- The value that gets loaded into sdata is determined
-- by which state we're exiting...
mx1:process(cstate, udata, uaddr)
begin
case cstate is
when "0000" => byte <= "101000001"; -- A0
when "0010" => byte <= "101000011"; -- A1
when "0101" => byte <= "101000001"; -- A0
when "0110" => byte <= uaddr & '1';
when "0111" => byte <= udata & '1';
when OTHERS => byte <= "000000001"; -- 0001,0011
end case;
end process;
-- The data register is 9 bits long (byte and ACK bit)
-- It is parallel loaded during the ACK cycle in states
-- 0000, 0001, 0010, 0011, 0101, 0110, and 0111;
ld_byte <= '1' when (bcnt(3) = '1' AND btck = '0' AND
cstate /= "0100" and cstate(3) = '0') else '0';
p7:process(reset_n, clk)
begin
if(reset_n = '0') then
sdata <= "111111111";
elsif(clk'event AND clk = '0') then
if(ld_byte = '1') then
sdata <= byte after 1 ns;
elsif((cstate /= "0101" AND cstate /= "0100" AND btck = '0' AND dly = '0') OR
(cstate = "0100" and btck = '1')) then
sdata <= sdata(7 downto 0) & sdi after 1 ns;
end if;
end if;
end process;
-- Start bits (data falling while btck is high) are generated as
-- we exit states 0000, 0010, and 0101; stop bits (data rising
-- while btck is high) are generated as we enter state 0101.
-- This is done with the STSP signal.
p4:process(reset_n, clk)
begin
if(reset_n = '0') then
stsp <= '1';
elsif(clk'event and clk = '0') then
if(((cstate = "0000" OR cstate = "0101") AND sten = '1' AND btck = '1') OR
(cstate = "0011"))then
stsp <= '0' after 1 ns;
elsif((cstate = "0101" AND bcnt = "0000" AND btck = '1') OR
(cstate = "010" AND bcnt(3) = '1')) then
stsp <= '1' after 1 ns;
end if;
end if;
end process;
-- The serial output is driven either by stsp when
-- outen is low, or by the MSBit of the shift register
-- when oten is high.
ctl_val <= '1' when (stsp = '1' OR (cstate = "100" AND
(bcnt(3) /= '1' OR ccnt = "11111111"))) else '0';
sdo <= ctl_val when (cstate = "0000" OR DLY = '1' OR cstate = "0100" OR
cstate = "0101")
else sdata(8);
sck <= '1' when (btck = '1' OR (stsp = '1' AND (cstate = "0000" OR cstate = "0101")))
else '0';
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -