📄 i2c_master.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 + -