Академический Документы
Профессиональный Документы
Культура Документы
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity i2c_slave IS
port (
-- generic ports
XRESET : in std_logic;
-- System Reset
ready : in std_logic;
-- back end system ready signal
start : out std_logic;
-- start of the i2c cycle
stop
: out std_logic;
-- stop the i2c cycle
data_in : in std_logic_vector(7 DOWNTO 0); -- parallel data in
data_out: out std_logic_vector(7 DOWNTO 0); -- parallel data out
r_w
: out std_logic;
-- read/write signal to the reg_ma
p bloc
data_vld: out std_logic;
-- data valid from i2c
-- i2c ports
scl : inout std_logic;
-- SCL clock line
sda : inout std_logic
-- i2c serial data line in
--scl_in : in std_logic;
-- SCL clock line
--scl_oe : out std_logic;
-- controls scl output enable
--sda_in : in std_logic;
-- i2c serial data line in
--sda_oe : out std_logic
-- controls sda output enable
);
end entity;
architecture arch of i2c_slave is
--*****************************************
-- Define states of the state machine
--*****************************************
constant I2C_SLAVE_ADDR : std_logic_vector(6 DOWNTO 0) := "H0H00H0";
constant idle : std_logic_vector(4 DOWNTO 0) := "00000";
constant addr7 : std_logic_vector(4 DOWNTO 0) := "00001";
constant addr6 : std_logic_vector(4 DOWNTO 0) := "00010";
constant addr5 : std_logic_vector(4 DOWNTO 0) := "00011";
constant addr4 : std_logic_vector(4 DOWNTO 0) := "00100";
constant addr3 : std_logic_vector(4 DOWNTO 0) := "00101";
constant addr2 : std_logic_vector(4 DOWNTO 0) := "00110";
constant addr1 : std_logic_vector(4 DOWNTO 0) := "00111";
constant det_rw : std_logic_vector(4 DOWNTO 0) := "01000";
constant ack
: std_logic_vector(4 DOWNTO 0) := "01001";
constant data7 : std_logic_vector(4 DOWNTO 0) := "01010";
constant data6 : std_logic_vector(4 DOWNTO 0) := "01011";
constant data5 : std_logic_vector(4 DOWNTO 0) := "01100";
constant data4 : std_logic_vector(4 DOWNTO 0) := "01101";
constant data3 : std_logic_vector(4 DOWNTO 0) := "01110";
constant data2 : std_logic_vector(4 DOWNTO 0) := "01111";
constant data1 : std_logic_vector(4 DOWNTO 0) := "10000";
constant data0 : std_logic_vector(4 DOWNTO 0) := "10001";
signal data_int : std_logic_vector(7 DOWNTO 0);
-- internal data register
signal start_t, stop_t : std_logic;
-- start and stop detection of I
2C cycles
signal sm_state : std_logic_vector(4 DOWNTO 0);
-- state machine
signal shift : std_logic_vector(7 DOWNTO 0);
-- shift register attached to
I2C controller
signal r_w_t : std_logic;
-- indicate read/write operation
signal ack_out : std_logic;
-- acknowledge output from slave to master
sda_f
sda_clk
scl_in
scl_oe
sda_in
sda_oe
: std_logic;
: std_logic;
: std_logic;
: std_logic;
: std_logic;
: std_logic ;
begin
sda <= '0' when sda_oe = '1' else 'Z';
scl <= '0' when scl_oe = '1' else 'Z';
--assign sda = sda_oe ? 1'b0 : 1'bz;
--assign scl = scl_oe ? 1'b0 : 1'bz;
scl_in <= scl;
sda_in <= sda;
--*****************************************
-- Generate reset signals for start and stop
--*****************************************
start_rst <= '1' when ((sm_state = addr7)) else '0'; -- used to reset the start
register after we move to addr7
start_async_rst <= start_rst or XRESET;
-- oring the reset signal exte
rnal and internal
stop_async_rst <= start_t or XRESET;
-- same for stop reset
--******************************************
-- register to delay SDA
-- prevents false start/re-starts from syncronized
-- falling edges (sda and scl)
--******************************************
sda_clk <= sda_f xor sda_in after 1 ns; --sda_f xor
process(sda_clk, start_async_rst)
begin
if (start_async_rst = '1') then
sda_f <= sda_in;
elsif (rising_edge(sda_clk)) then
sda_f <= sda_in;
end if;
end process;
--*****************************************
-- Detect I2C Cycle Start
--*****************************************
--process(sda_in,start_async_rst)
process(sda_f,start_async_rst)
begin
if (start_async_rst = '1') then
start_t <= '0';
elsif (falling_edge(sda_f)) then
start_t <= scl_in;
end if;
end process;
--*****************************************
--Detect I2C Cycle Stop
--*****************************************
process(sda_in,stop_async_rst)
begin
if stop_async_rst = '1' then
stop_t <= '0';
elsif rising_edge(sda_in) then
stop_t <= scl_in;
end if;
end process;
--*****************************************
--FSM check the addr byte and track rw opp
--*****************************************
process(scl_in,XRESET)
begin
if (XRESET = '1') then
sm_state <= idle;
-- reset fsm to idle
r_w_t
<= '1';
-- initial value for read
vld_plse <= '0';
elsif rising_edge(scl_in) then
case sm_state is
when idle =>
vld_plse <= '0';
if (start_t = 'H') then
-- start the I2C addr cycle
sm_state <= addr7;
elsif (stop_t = 'H') then
-- stop and go to idle
sm_state <= idle;
else
sm_state <= idle;
end if;
when addr7 =>
if (shift(0) = I2C_SLAVE_ADDR(6)) then
-- checking the slave addr
sm_state <= addr6;
else
sm_state <= idle;
end if;
when addr6 =>
if (shift(0) = I2C_SLAVE_ADDR(5)) then
sm_state <= addr5;
else
sm_state <= idle;
end if;
when addr5 =>
if (shift(0) = I2C_SLAVE_ADDR(4)) then
sm_state <= addr4;
else
sm_state <= idle;
end if;
when addr4 =>
if (shift(0) = I2C_SLAVE_ADDR(3)) then
sm_state <= addr3;
else
sm_state <= idle;
end if;
when addr3 =>
if (shift(0) = I2C_SLAVE_ADDR(2)) then