📄 altera_avalon_i2c_slave.vhd
字号:
--------------------------------------------------------------------------
-- I2C Slave with avalon integration example. by R. N. Hill rhill@altera.com
-- Not fully tested - use at your own risk!
--------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity altera_avalon_i2c_slave is
port (
--------------------------------------------------------------------------
-- system inputs
--------------------------------------------------------------------------
signal sys_clk : IN STD_LOGIC;
signal sys_reset_n : IN STD_LOGIC;
--------------------------------------------------------------------------
-- Avalon interface
--------------------------------------------------------------------------
-- inputs:
signal avalon_write : IN STD_LOGIC;
signal avalon_writedata : IN STD_LOGIC_VECTOR(7 downto 0);
signal avalon_address : IN STD_LOGIC_VECTOR(1 downto 0);
-- outputs:
signal avalon_readdata : OUT STD_LOGIC_VECTOR(7 downto 0);
signal avalon_interrupt : OUT STD_LOGIC;
--------------------------------------------------------------------------
-- i2c interface
--------------------------------------------------------------------------
signal scl : IN STD_LOGIC;
signal sda : INOUT STD_LOGIC
);
end entity altera_avalon_i2c_slave;
architecture rtl of altera_avalon_i2c_slave is
--------------------------------------------------------------------------
-- internal registers - Device Driver interface
--------------------------------------------------------------------------
--
-- register bit map address register name
-- --------------------------------- --------- -------------
--
-- 7 0
-- +---+---+---+---+---+---+---+---+
-- |N/A| I2C ADDRESS | base i2c_address
-- +---+---+---+---+---+---+---+---+
-- | I2C DATA | base + 0x4 i2c_data
-- +---+---+---+---+---+---+---+---+
-- | N/A |IM | base + 0x8 i2c_int_mask
-- +---+---+---+---+---+---+---+---+
-- | N/A | I | base + 0xC i2c_interrupt
-- +---+---+---+---+---+---+---+---+
--
--------------------------------------------------------------------------
-- register definitions:
--------------------------------------------------------------------------
--
-- i2c_address : defines the slave address that this i2c slave will respond to
--
-- i2c_data : holds data received from last write to the slave. Also holds
-- : the data that will be sent from the next read from the slave
--
-- i2c_int_mask : mask for the interrupt line to cpu. This is a simple mask. This bit
-- : does not affect how the interrupts are generated. The interrupt
-- : state can still be polled even if the mask is not set
--
-- i2c_interrupt : interrupt state of the slave. reset by writing to slave (any
-- : addr). The interrupt line to the CPU mirrors this signal when
-- : unmasked
--
--------------------------------------------------------------------------
signal i2c_address : std_logic_vector(6 downto 0);
signal i2c_data : std_logic_vector(7 downto 0);
signal i2c_int_mask : std_logic;
signal i2c_interrupt : std_logic;
--------------------------------------------------------------------------
-- i2c signals
--------------------------------------------------------------------------
signal sda_pad_o : std_logic;
signal scl_pad_i : std_logic;
signal sda_pad_i : std_logic;
signal last_scl_pad_i : std_logic;
signal last_sda_pad_i : std_logic;
signal scl_metafilt : std_logic_vector(3 downto 0);
signal sda_metafilt : std_logic_vector(3 downto 0);
-------------------------------------------------------------------------- -- i2c slave state machine signals
--------------------------------------------------------------------------
constant I2C_SLAVE_STATE_IDLE : std_logic_vector(6 downto 0) := "0000001";
constant I2C_SLAVE_STATE_START : std_logic_vector(6 downto 0) := "0000010";
constant I2C_SLAVE_STATE_RX_ADDR : std_logic_vector(6 downto 0) := "0000100";
constant I2C_SLAVE_STATE_ADDR_ACK : std_logic_vector(6 downto 0) := "0001000";
constant I2C_SLAVE_STATE_READ : std_logic_vector(6 downto 0) := "0010000";
constant I2C_SLAVE_STATE_WRITE : std_logic_vector(6 downto 0) := "0100000";
constant I2C_SLAVE_STATE_STOP : std_logic_vector(6 downto 0) := "1000000";
signal i2c_slave_state : std_logic_vector(6 downto 0);
signal i2c_counter : unsigned(3 downto 0);
signal i2c_shift_reg : std_logic_vector(7 downto 0);
signal i2c_read_writen : std_logic;
signal i2c_set_interrupt : std_logic;
signal i2c_rx_data : std_logic_vector(7 downto 0);
signal i2c_set_data : std_logic;
begin
--------------------------------------------------------------------------
-- i2c bidirectional wire xover
--------------------------------------------------------------------------
sda <= '0' when (sda_pad_o = '0') else 'Z';
--------------------------------------------------------------------------
-- interrupt output control
--------------------------------------------------------------------------
avalon_interrupt <= i2c_interrupt when i2c_int_mask = '1' else '0';
--------------------------------------------------------------------------
-- avalon/register interface logic
--------------------------------------------------------------------------
avalon_readdata <= "0" & i2c_address when avalon_address = "00" else
i2c_data when avalon_address = "01" else
"0000000" & i2c_int_mask when avalon_address = "10" else
"0000000" & i2c_interrupt;-- when avalon_address = "11"
register_io : process(sys_clk,sys_reset_n)
begin
if sys_reset_n = '0' then
i2c_address <= (others => '0');
i2c_data <= (others => '0');
i2c_int_mask <= '0';
i2c_interrupt <= '0';
elsif sys_clk'EVENT and sys_clk = '1' then
if avalon_write = '1' then
i2c_interrupt <= '0';
if avalon_address = "00" then
i2c_address <= avalon_writedata(6 downto 0);
i2c_data <= i2c_data;
i2c_int_mask <= i2c_int_mask;
elsif avalon_address = "01" then
i2c_address <= i2c_address;
i2c_data <= avalon_writedata;
i2c_int_mask <= i2c_int_mask;
elsif avalon_address = "10" then
i2c_address <= i2c_address;
i2c_data <= i2c_data;
i2c_int_mask <= avalon_writedata(0);
else --if avalon_address = "11" then
i2c_address <= i2c_address;
i2c_data <= i2c_data;
i2c_int_mask <= i2c_int_mask;
end if;
else
i2c_address <= i2c_address;
i2c_int_mask <= i2c_int_mask;
if i2c_set_interrupt = '1' then
i2c_interrupt <= '1';
else
i2c_interrupt <= i2c_interrupt;
end if;
if i2c_set_data = '1' then
i2c_data <= i2c_rx_data;
else
i2c_data <= i2c_data;
end if;
end if;
end if;
end process register_io;
--------------------------------------------------------------------------
-- slave processing logic/state machine
--------------------------------------------------------------------------
i2c_slave : process (sys_clk,sys_reset_n)
begin
if sys_reset_n = '0' then
i2c_set_interrupt <= '0';
i2c_slave_state <= I2C_SLAVE_STATE_IDLE;
i2c_counter <= (others => '0');
i2c_shift_reg <= (others => '0');
i2c_read_writen <= '0';
sda_pad_o <= '1';
scl_pad_i <= scl;
sda_pad_i <= sda;
scl_metafilt <= (others => '0');
sda_metafilt <= (others => '0');
last_scl_pad_i <= scl_pad_i;
last_sda_pad_i <= sda_pad_i;
i2c_set_data <= '0';
i2c_rx_data <= (others => '0');
elsif sys_clk'EVENT and sys_clk = '1' then
--------------------------------------------------------------------------
if i2c_slave_state = I2C_SLAVE_STATE_IDLE then
--------------------------------------------------------------------------
i2c_set_data <= '0';
i2c_rx_data <= i2c_rx_data;
i2c_set_interrupt <= '0';
i2c_counter <= (others => '0');
i2c_shift_reg <= (others => '0');
i2c_read_writen <= '0';
sda_pad_o <= '1';
if last_sda_pad_i = '1' and sda_pad_i = '0' AND scl_pad_i = '1' then
i2c_slave_state <= I2C_SLAVE_STATE_START; -- data going low when clock is still high is the start condition - initiate reception
else
i2c_slave_state <= I2C_SLAVE_STATE_IDLE;
end if;
--------------------------------------------------------------------------
elsif i2c_slave_state = I2C_SLAVE_STATE_START then
--------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -