194 lines
5.7 KiB
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;
|