hdet/fpga/src/i2c/master/i2c_wrapper.vhdl

194 lines
5.7 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity i2c_wrapper is
generic ( prescale : std_logic_vector(15 downto 0) := x"00c8");
port (
wb_clk_i : in std_logic;
wb_rst_i : in std_logic;
wb_adr_i : in std_logic_vector(15 downto 0);
wb_dat_i : in std_logic_vector(7 downto 0);
wb_dat_o : out std_logic_vector(7 downto 0);
wb_we_i : in std_logic;
wb_stb_i : in std_logic;
wb_ack_o : out std_logic;
scl_i : in std_logic;
scl_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
debug : out std_logic_vector(3 downto 0)
);
end;
architecture i2c_wrapper of i2c_wrapper is
signal wb_adr : unsigned(2 downto 0);
signal wb_dati : std_logic_vector(7 downto 0);
signal wb_dato : std_logic_vector(7 downto 0);
signal wb_we : std_logic;
signal wb_stb : std_logic;
signal wb_cyc : std_logic;
signal wb_ack : std_logic;
signal wb_inta : std_logic;
signal wb_dat_oq : std_logic_vector(7 downto 0);
signal cnt : unsigned(3 downto 0);
signal wb_dowrite : std_logic;
signal wb_doread : std_logic;
signal end_cnt : integer range 0 to 11;
type i2c_rec is record
adr : unsigned(2 downto 0);
dat : std_logic_vector(7 downto 0);
int : std_logic;
end record;
type i2c_mem is ARRAY(0 to 11) of i2c_rec;
signal dat : i2c_mem;
type i2c_states is (IDLE, I2C_GO, I2C_WAIT_INT, I2C_GET_RXDAT, I2C_WB_ACK);
signal i2c_sm : i2c_states;
signal scl : std_logic;
signal sda : std_logic;
signal scl_oen : std_logic;
signal sda_oen : std_logic;
signal i2c_init_done : std_logic;
begin
scl_o <= scl when scl_oen = '0' else '1';
sda_o <= sda when sda_oen = '0' else '1';
wb_dat_o <= wb_dat_oq;
i2c_master : entity work.i2c_master_top
generic map( ARST_LVL => '1' )
port map (
-- wishbone signals
wb_clk_i => wb_clk_i,
wb_rst_i => wb_rst_i,
arst_i => wb_rst_i,
wb_adr_i => std_logic_vector(wb_adr),
wb_dat_i => wb_dati,
wb_dat_o => wb_dato,
wb_we_i => wb_we,
wb_stb_i => wb_stb,
wb_cyc_i => wb_cyc,
wb_ack_o => wb_ack,
wb_inta_o => wb_inta,
-- i2c lines
scl_pad_i => scl_i,
scl_pad_o => scl,
scl_padoen_o => scl_oen,
sda_pad_i => sda_i,
sda_pad_o => sda,
sda_padoen_o => sda_oen
);
i2c_write: process (wb_clk_i, wb_rst_i)
begin
if rising_edge(wb_clk_i) then
if wb_rst_i = '1' then
wb_dat_oq <= (others => '0');
cnt <= (others => '0');
i2c_init_done <= '0';
wb_dowrite <= '0';
wb_doread <= '0';
end_cnt <= 0;
else
dat <= dat;
if wb_ack = '1' and i2c_sm = I2C_GO then
cnt <= cnt + "1";
elsif i2c_sm = IDLE and i2c_init_done = '1' then
cnt <= "0011";
elsif i2c_sm = IDLE and i2c_init_done = '0' then
cnt <= "0000";
end if;
if i2c_sm = IDLE and wb_stb_i = '1' then
if wb_we_i = '1' then
-- PRESCALE Register enable core and interrupt
dat <= (("000", prescale(7 downto 0),'0'), ("001", prescale(15 downto 8),'0'), ("010", x"c0",'0'),
-- ADDRESS STA and WR bit DATA/REG STA and WR
("011", x"EC", '0'), ("100", x"90",'1'), ("011", x"ff", '0'), ("100", x"90",'1'),
-- DATA STO and WR
("011", x"ff",'0'), ("100", x"50", '1'));
dat(3).dat <= wb_adr_i(15 downto 0);
dat(5).dat <= wb_adr_i( 7 downto 0);
dat(8).dat <= wb_dat_i;
end_cnt <= 9;
else
dat <= (("000", prescale(7 downto 0),'0'), ("001", prescale(15 downto 8),'0'), ("010", x"c0",'0'),
-- ADDRESS STA and WR bit DATA/REG WR
("011", x"EC", '0'), ("100", x"91",'1'), ("011", x"ff", '0'), ("100", x"11", '1'),
-- ADDRESS STA,WR STO, RD, NACK
("011", x"ED", '0'), ("100", x"91",'1'), ("100", x"69", '1'), ("111", x"00", '0'), ("111", x"00", '0'));
dat(3).dat <= wb_adr_i(15 downto 9) & '0'; -- address write
dat(5).dat <= wb_adr_i( 7 downto 0); -- memory location
dat(7).dat <= wb_adr_i(15 downto 9) & '1'; -- address read
end_cnt <= 10;
end if;
end if;
i2c_init_done <= i2c_init_done;
if i2c_sm = I2C_GO and cnt = "0010" then
i2c_init_done <= '1';
end if;
if i2c_sm = I2C_GET_RXDAT and wb_ack = '1' then
wb_dat_oq <= wb_dato;
end if;
case i2c_sm is
when IDLE =>
if (wb_stb_i = '1') then
i2c_sm <= I2C_GO;
end if;
when I2C_GO =>
wb_dowrite <= '1';
if wb_ack = '1' and dat(to_integer(cnt)).int = '1' then
i2c_sm <= I2C_WAIT_INT;
wb_dowrite <= '0';
elsif wb_ack = '1' and dat(to_integer(cnt)).int = '0' then
if to_integer(cnt) = end_cnt then
i2c_sm <= I2C_GET_RXDAT;
end if;
wb_dowrite <= '0';
end if;
when I2C_WAIT_INT =>
wb_doread <= '1';
if wb_ack = '1' and wb_dato(1) = '0' then
wb_doread <= '0';
if to_integer(cnt) = end_cnt then
i2c_sm <= I2C_GET_RXDAT;
else
i2c_sm <= I2C_GO;
end if;
end if;
when I2C_GET_RXDAT =>
wb_doread <= '1';
if wb_ack = '1' then
wb_doread <= '0';
i2c_sm <= I2C_WB_ACK;
end if;
when I2C_WB_ACK =>
i2c_sm <= IDLE;
end case;
end if;
end if;
end process;
wb_ack_o <= '1' when i2c_sm = I2C_WB_ACK else '0';
wb_dati <= dat(to_integer(cnt)).dat;
wb_adr <= dat(to_integer(cnt)).adr when wb_dowrite = '1' else
"011" when i2c_sm = I2C_GET_RXDAT else
"100";
wb_cyc <= wb_stb;
wb_stb <= '1' when (wb_dowrite = '1' or wb_doread = '1') and wb_ack = '0' else '0';
wb_we <= wb_dowrite;
debug(3 downto 0) <= std_logic_vector(cnt);
end i2c_wrapper;