-- 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;