-- i2c interface
-- scl_rising
-- scl_stretch_o
-- sda_o
-- control interface
-- clk_i
-- rst_in
-- start_write_i
-- write interface
-- ready_o
-- valid_i
-- write_data
library ieee;
use ieee.std_logic_1164.all;
library utils;
entity tx is
port (
clk_i : in std_logic;
rst_in : in std_logic;
start_write_i : in std_logic;
rst_i2c_i : in std_logic; -- Reset rx circuitry
clear_buffer_i : in std_logic;
done_o : out std_logic;
unexpected_sda_o : out std_logic;
noack_o : out std_logic;
scl_rising_i : in std_logic;
scl_falling_delayed_i : in std_logic;
scl_stretch_o : out std_logic;
sda_i : in std_logic;
sda_enable_o : out std_logic;
ready_o : out std_logic;
valid_i : in std_logic;
write_data_i : in std_logic_vector(7 downto 0));
end entity tx;
architecture a1 of tx is
-- IDLE - not doing anything
-- SENDING - data are in the buffer, being sent
-- WAITING_FOR_SEND there were data written to the buffer, but cannot send now
-- WAITING_FOR_DATA should be sending, but there are no data - stretching
type tx_state_t is (IDLE, WAITING_FOR_FALLING_EDGE, SENDING, ACK, WAITING_FOR_DATA);
signal curr_state : tx_state_t;
signal next_state : tx_state_t;
type tx_buffers is array (0 to 1) of std_logic_vector(8 downto 0);
signal curr_tx_buffers : tx_buffers;
signal next_tx_buffers : tx_buffers;
-- Index to save next new data to.
signal curr_saving_buffer_index : integer range 0 to 1;
signal next_saving_buffer_index : integer range 0 to 1;
signal curr_tx_buffer_index : integer range 0 to 1;
signal next_tx_buffer_index : integer range 0 to 1;
signal curr_tx_buffers_filled : std_logic_vector(1 downto 0);
signal next_tx_buffers_filled : std_logic_vector(1 downto 0);
signal curr_done : std_logic;
signal next_done : std_logic;
signal tx_buffer : std_logic_vector(8 downto 0);
signal tx_buffer_filled : std_logic;
signal curr_scl : std_logic;
signal next_scl : std_logic;
signal ready : std_logic;
begin -- architecture a1
scl_stretch_o <= '1' when curr_state = WAITING_FOR_DATA and curr_done = '0' else '0';
ready_o <= ready;
sda_enable_o <= not tx_buffer(8) when curr_state = SENDING else '0';
unexpected_sda_o <= '1' when curr_state = SENDING and sda_i /= tx_buffer(8) and scl_rising_i = '1' else '0';
noack_o <= '1' when curr_state = ACK and sda_i = '1' and scl_rising_i = '1' else '0';
ready <= '0' when curr_tx_buffers_filled(curr_saving_buffer_index) = '1' else '1';
tx_buffer <= curr_tx_buffers(curr_tx_buffer_index);
tx_buffer_filled <= curr_tx_buffers_filled(curr_tx_buffer_index);
next_scl <= '1' when scl_rising_i = '1' else
'0' when scl_falling_delayed_i = '1' else
curr_scl;
next_tx_buffer_index <= (curr_tx_buffer_index + 1) mod 2 when tx_buffer(7 downto 0) = "10000000" and scl_falling_delayed_i = '1' else
curr_tx_buffer_index;
next_saving_buffer_index <= (curr_saving_buffer_index + 1) mod 2 when ready = '1' and valid_i = '1' else
curr_saving_buffer_index;
done_o <= curr_done and not next_done;
next_done <= '1' when curr_state = ACK and next_state /= ACK else
'1' when curr_done = '1' and scl_falling_delayed_i = '0' else
'0';
set_next_tx_buffers: process(all) is
begin -- process set_next_tx_buffer
next_tx_buffers <= curr_tx_buffers;
if ready = '1' and valid_i = '1' then
next_tx_buffers(curr_saving_buffer_index) <= write_data_i & '1';
end if;
if curr_state = SENDING and scl_falling_delayed_i = '1' then
next_tx_buffers(curr_tx_buffer_index) <= tx_buffer(7 downto 0) & '0';
end if;
end process set_next_tx_buffers;
set_next_buffer_filled: process(all) is
begin -- process set_next_buffer_filled
next_tx_buffers_filled <= curr_tx_buffers_filled;
if tx_buffer(7 downto 0) = "10000000" and scl_falling_delayed_i = '1' then
next_tx_buffers_filled(curr_tx_buffer_index) <= '0';
end if;
if ready = '1' and valid_i = '1' then
next_tx_buffers_filled(curr_saving_buffer_index) <= '1';
end if;
end process set_next_buffer_filled;
set_next_state: process(all) is
variable start_sending : std_logic := '0';
variable override_tx_buffer_filled : std_logic;
begin -- process set_next_state
start_sending := '0';
next_state <= curr_state;
override_tx_buffer_filled := tx_buffer_filled;
if curr_state = IDLE then
if start_write_i = '1' then
start_sending := '1';
end if;
elsif curr_state = WAITING_FOR_FALLING_EDGE then
if scl_falling_delayed_i = '1' then
next_state <= SENDING;
end if;
elsif curr_state = SENDING then
if tx_buffer(7 downto 0) = "10000000" and scl_falling_delayed_i = '1' then
next_state <= ACK;
end if;
elsif curr_state = ACK then
if scl_rising_i = '1' then
if start_write_i = '1' then
override_tx_buffer_filled := curr_tx_buffers_filled(next_tx_buffer_index);
start_sending := '1';
else
next_state <= IDLE;
end if;
end if;
elsif curr_state = WAITING_FOR_DATA then
if valid_i = '1' then
start_sending := '1';
end if;
end if;
if start_sending = '1' then
if override_tx_buffer_filled = '0' and valid_i = '0' then
next_state <= WAITING_FOR_DATA;
elsif curr_scl = '0' and scl_rising_i = '0' then
next_state <= SENDING;
else
next_state <= WAITING_FOR_FALLING_EDGE;
end if;
end if;
end process set_next_state;
set_regs: process (clk_i) is
begin -- process set_next
if rising_edge(clk_i) then -- rising clock edge
if rst_in = '0' or clear_buffer_i = '1' then -- synchronous reset (active low)
curr_state <= IDLE;
curr_tx_buffers <= (others => (others => '0'));
curr_tx_buffer_index <= 0;
curr_tx_buffers_filled <= "00";
curr_saving_buffer_index <= 0;
curr_scl <= '1'; -- assume 1 (the default, no one transmitting)
curr_done <= next_done;
else
curr_state <= next_state;
curr_tx_buffers <= next_tx_buffers;
curr_tx_buffer_index <= next_tx_buffer_index;
curr_tx_buffers_filled <= next_tx_buffers_filled;
curr_saving_buffer_index <= next_saving_buffer_index;
curr_scl <= next_scl;
curr_done <= next_done;
end if;
if rst_i2c_i = '1' then
curr_state <= IDLE;
curr_scl <= '1'; -- assume 1 (the default, no one transmitting)
curr_done <= '0';
end if;
end if;
end process set_regs;
end architecture a1;