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

📄 altera_avalon_i2c_slave.vhd

📁 i2c从设备的源码
💻 VHD
📖 第 1 页 / 共 2 页
字号:
--------------------------------------------------------------------------
-- 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 + -