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

📄 i2c_master.vhd

📁 实现基于Avalon总线架构的I2C控制器!可实现OV7620等数字摄像头的配置功能!
💻 VHD
字号:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

--------------------------------------------
ENTITY I2C_Master IS
   PORT(
		Clk        :    IN STD_LOGIC;
		Reset_n    :    IN STD_LOGIC;       
       
       --Avalon-MM Slave Interface
		Avs_s1_chipselect    :    IN STD_LOGIC;	
		Avs_s1_address       :    IN STD_LOGIC_VECTOR(2 DOWNTO 0);
		Avs_s1_read          :    IN STD_LOGIC;
		Avs_s1_readdata      :    OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
		Avs_s1_write         :    IN STD_LOGIC;
		Avs_s1_writedata     :    IN STD_LOGIC_VECTOR(31 DOWNTO 0);
--      Avs_s1_irq           :    OUT STD_LOGIC;
--      Avs_s1_waitrequest   :    OUT STD_LOGIC;
       
       -- Sortie I2C
--        I2C_SCL    :    INOUT STD_LOGIC;                -- i2c clock line output
--        I2C_SDA    :    INOUT STD_LOGIC                 -- i2c data line output
   
--        scl_pad_i            :    IN STD_LOGIC;                 -- i2c clock line input
        scl_pad_o            :    OUT STD_LOGIC;                -- i2c clock line output
--        scl_padoen_o         :    OUT STD_LOGIC;                -- i2c clock line output enable, active low
        sda_pad_i            :    IN STD_LOGIC;                 -- i2c data line input
        sda_pad_o            :    OUT STD_LOGIC;                -- i2c data line output
        sda_padoen_o         :    OUT STD_LOGIC                 -- i2c data line output enable, active low
    );
END I2C_Master;

--------------------------------------------

ARCHITECTURE rtl OF I2C_Master IS
	-- registers
	SIGNAL prer_reg : STD_LOGIC_VECTOR(15 DOWNTO 0);     -- clock prescale register
	SIGNAL ctr_reg  : STD_LOGIC_VECTOR(7 DOWNTO 0);      -- control register
	SIGNAL txr_reg  : STD_LOGIC_VECTOR(7 DOWNTO 0);      -- transmit register
	SIGNAL rxr_reg  : STD_LOGIC_VECTOR(7 DOWNTO 0);      -- receive register
	SIGNAL cr_reg   : STD_LOGIC_VECTOR(7 DOWNTO 0);      -- command register
	SIGNAL sr_reg   : STD_LOGIC_VECTOR(7 DOWNTO 0);      -- status register
	
--	SIGNAL scl_pad_i     : STD_LOGIC;
--	SIGNAL scl_pad_o     : STD_LOGIC;
--	SIGNAL scl_padoen_o  : STD_LOGIC;
--	SIGNAL sda_pad_i     : STD_LOGIC;
--	SIGNAL sda_pad_o     : STD_LOGIC;
--	SIGNAL sda_padoen_o  : STD_LOGIC;

	-- internal reset signal
--	signal rst_i : std_logic;
	-- wishbone write access
--	signal wb_wacc : std_logic;
	-- internal acknowledge signal
--	signal iack_o : std_logic;

	-- done signal: command completed, clear command register
	SIGNAL done : STD_LOGIC;

	-- command register signals
	SIGNAL sta, sto, rd, wr, ack, iack : STD_LOGIC;

	SIGNAL core_en : STD_LOGIC;                      -- core enable signal
--	SIGNAL ien     : STD_LOGIC;                      -- interrupt enable signal

	-- status register signals
	SIGNAL irxack, rxack : STD_LOGIC;           -- received aknowledge from slave
	SIGNAL tip           : STD_LOGIC;           -- transfer in progress
--	SIGNAL irq_flag      : STD_LOGIC;           -- interrupt pending flag
	SIGNAL i2c_busy      : STD_LOGIC;           -- i2c bus busy (start signal detected)
--	SIGNAL i2c_al, al    : STD_LOGIC;           -- arbitration lost

COMPONENT i2c_master_byte_ctrl is
	PORT(
		Clk        :    IN STD_LOGIC;
--		rst        :    IN STD_LOGIC; -- synchronous active high reset (WISHBONE compatible)
		Reset_n    :    IN STD_LOGIC; -- asynchornous active low reset (FPGA compatible)
		ena        :    IN STD_LOGIC; -- core enable signal
		clk_cnt    :    IN STD_LOGIC_VECTOR(15 DOWNTO 0);	-- 4x SCL

		-- input signals
		start      :    IN STD_LOGIC;
		stop       :    IN STD_LOGIC;
		read_en    :    IN STD_LOGIC;
		write_en   :    IN STD_LOGIC;
		ack_in     :    IN STD_LOGIC;
		din        :    IN STD_LOGIC_VECTOR(7 DOWNTO 0);

		-- output signals
		cmd_ack    :    OUT STD_LOGIC;
		ack_out    :    OUT STD_LOGIC;
		i2c_busy   :    OUT STD_LOGIC;
--		i2c_al     :    OUT STD_LOGIC;
		dout       :    OUT STD_LOGIC_VECTOR(7 DOWNTO 0);

		-- i2c lines
--		scl_i      :    IN STD_LOGIC;  -- i2c clock line input
		scl_o      :    OUT STD_LOGIC; -- i2c clock line output
--		scl_oen    :    OUT STD_LOGIC; -- i2c clock line output enable, active low
		sda_i      :    IN STD_LOGIC;  -- i2c data line input
		sda_o      :    OUT STD_LOGIC; -- i2c data line output
		sda_oen    :    OUT STD_LOGIC  -- i2c data line output enable, active low
	);
END COMPONENT i2c_master_byte_ctrl;	

BEGIN
	
	PROCESS(Clk, Reset_n)---write data to regs;
	BEGIN
		IF (Reset_n = '0') THEN
			prer_reg <= (OTHERS => '0');
			ctr_reg  <= (OTHERS => '0');
			txr_reg  <= (OTHERS => '0');
		ELSIF (Clk'EVENT AND Clk = '1') THEN
			IF Avs_s1_chipselect = '1' THEN
				IF Avs_s1_write = '1' THEN
					CASE Avs_s1_address IS
						WHEN "000" => prer_reg <= Avs_s1_writedata(15 DOWNTO 0);
						WHEN "001" => ctr_reg  <= Avs_s1_writedata(7 DOWNTO 0);
						WHEN "010" => txr_reg  <= Avs_s1_writedata(7 DOWNTO 0);
						WHEN "011" => NULL;--write to CR, avoid executing the others clause
						WHEN OTHERS =>prer_reg <= (OTHERS => 'X');
									  ctr_reg  <= (OTHERS => 'X');
	                                  txr_reg  <= (OTHERS => 'X');
					END CASE;
				END IF;
				IF Avs_s1_read = '1' THEN
					CASE Avs_s1_address IS
						WHEN "000" => Avs_s1_readdata  <= "00000000"&"00000000"&prer_reg;
						WHEN "001" => Avs_s1_readdata  <= "00000000"&"00000000"&"00000000"&ctr_reg;
						WHEN "010" => Avs_s1_readdata  <= "00000000"&"00000000"&"00000000"&rxr_reg;
						WHEN "011" => Avs_s1_readdata  <= "00000000"&"00000000"&"00000000"&sr_reg;
						WHEN "100" => Avs_s1_readdata  <= "00000000"&"00000000"&"00000000"&txr_reg;
						WHEN "101" => Avs_s1_readdata  <= "00000000"&"00000000"&"00000000"&cr_reg;
						WHEN OTHERS => Avs_s1_readdata <= (OTHERS=>'0');
					END CASE;
				END IF;
			END IF;	
		END IF;
	END PROCESS;
	
	-- generate command register
	gen_cr: PROCESS(Clk, Reset_n)
	BEGIN
	    IF (Reset_n = '0') THEN
	        cr_reg <= (others => '0');
	    ELSIF (Clk'EVENT AND Clk = '1') THEN
			IF (Avs_s1_chipselect AND Avs_s1_write) = '1' THEN
				IF ( (core_en = '1') AND (Avs_s1_address = "011") ) THEN
	                -- only take new commands when i2c core enabled
	                -- pending commands are finished
					cr_reg <= Avs_s1_writedata(7 DOWNTO 0);
	            END IF;
		    ELSIF (done = '1' ) THEN
				cr_reg(7 DOWNTO 4) <= (OTHERS => '0'); 
						-- clear command bits when command done or arbitration lost
			ELSE
				cr_reg(2 DOWNTO 0) <= (OTHERS => '0');  
					    -- reserved bits, always '0'
				--cr_reg(0) <= '0'; -- clear IRQ_ACK bit
			END IF;
		END IF;
	END PROCESS gen_cr;
	
	-- decode command register
	sta  <= cr_reg(7);
	sto  <= cr_reg(6);
	rd   <= cr_reg(5);
	wr   <= cr_reg(4);
	ack  <= cr_reg(3);
--	iack <= cr_reg(0);

	-- decode control register
	core_en <= ctr_reg(7);
--	ien     <= ctr_reg(6);
		
	-- hookup byte controller block
	byte_ctrl: i2c_master_byte_ctrl PORT MAP (
		Clk     => Clk,
		Reset_n => Reset_n,
		ena     => core_en,
		clk_cnt => prer_reg,
-- input signals
		start    => sta,
		stop     => sto,
		read_en  => rd,
		write_en => wr,
		ack_in   => ack,
		din      => txr_reg,
-- output signals
		cmd_ack  => done,
		ack_out  => irxack,
		i2c_busy => i2c_busy,
--		i2c_al,
		dout     => rxr_reg,
-- i2c lines
--		scl_i    => scl_pad_i,
		scl_o    => scl_pad_o,
--		scl_oen  => scl_padoen_o,
		sda_i    => sda_pad_i,
		sda_o    => sda_pad_o,
		sda_oen  => sda_padoen_o
	);

	-- status register block + interrupt request signal
	st_irq_block : BLOCK
	BEGIN
	    -- generate status register bits
	    gen_sr_bits: PROCESS (Clk, Reset_n)
	    BEGIN
	        IF (Reset_n = '0') THEN
--	          al       <= '0';
	          rxack    <= '0';
	          tip      <= '0';
--	          irq_flag <= '0';
	        ELSIF (Clk'EVENT AND Clk = '1') THEN
--	            al       <= i2c_al OR (al AND (NOT sta));
	            rxack    <= irxack;
	            tip      <= (rd OR wr);
	            -- interrupt request flag is always generated
--	            irq_flag <= (done OR i2c_al OR irq_flag) AND (NOT iack);
	        END IF;
	    END PROCESS gen_sr_bits;

	    -- generate interrupt request signals
--	    gen_irq: PROCESS (Clk, Reset_n)
--	    BEGIN
--	        IF (Reset_n = '0') THEN
--	          Avs_s1_irq <= '0';
--	        ELSIF (Clk'EVENT AND Clk = '1') THEN
	            -- interrupt signal is only generated when IEN (interrupt enable bit) is set
--	            Avs_s1_irq <= irq_flag AND ien;
--	        END IF;
--	    END PROCESS gen_irq;

	    -- assign status register bits
	    sr_reg(7)          <= rxack;
	    sr_reg(6)          <= i2c_busy;
	    sr_reg(5)          <= tip;
	    sr_reg(4 DOWNTO 0) <= (OTHERS => '0'); -- reserved
--	    sr_reg(1)          <= tip;
--	    sr_reg(0)          <= irq_flag;
	END BLOCK;
	
--	I2C_SCL <= scl_pad_o WHEN (scl_padoen_o = '0') ELSE 'Z';
--	I2C_SDA <= sda_pad_o WHEN (sda_padoen_o = '0') ELSE 'Z';
--	scl_pad_i <= I2C_SCL; 
--	sda_pad_i <= I2C_SDA; 
	
END ARCHITECTURE rtl;

⌨️ 快捷键说明

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