From 18c09799a7abcd972484998e37e7b537b15ab6f3 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Thu, 28 Dec 2023 15:39:06 +0100 Subject: [PATCH] feat: add i2c slave state entity --- src/i2c/slave_state.vhd | 94 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/i2c/slave_state.vhd diff --git a/src/i2c/slave_state.vhd b/src/i2c/slave_state.vhd new file mode 100644 index 0000000..0355f82 --- /dev/null +++ b/src/i2c/slave_state.vhd @@ -0,0 +1,94 @@ +library ieee; +use ieee.std_logic_1164.all; + +entity i2c_slave_state is + port ( + clk_i : in std_logic; + rst_in : in std_logic; + + sda_i : in std_logic; + scl_i : in std_logic; + scl_pulse_i : in std_logic; + + start_condition_i : in std_logic; + stop_condition_i : in std_logic; + + rw_i : in std_logic; + address_detect_success_i : in std_logic; + address_detect_fail_i : in std_logic; + address_detect_start_o : out std_logic; + address_detect_active_o : out std_logic; + + expects_ack_o : out std_logic; + generate_ack_o : out std_logic; + receive_o : out std_logic; + transmit_o : out std_logic; + start_receive_o : out std_logic; + start_transmit_o : out std_logic + ); +end entity i2c_slave_state; + +architecture a1 of i2c_slave_state is + type slave_state is ( + BUS_FREE, -- there is no communication on the bus + BUS_ADDRESS, -- communication on the bus just started, listening for + -- address + RECEIVING, -- we are receiving data + TRANSMITTING, -- we are transmitting data + BUS_BUSY); -- bus is taken, different slave communicating + + signal curr_state : slave_state; + signal next_state : slave_state; + + constant TRANSMIT_LEN : integer := 9; + signal curr_data_position : integer range 0 to TRANSMIT_LEN-1; + signal next_data_position : integer range 0 to TRANSMIT_LEN-1; + + signal communicating_with_master : std_logic; +begin -- architecture a1 + + communicating_with_master <= '1' when curr_state = BUS_ADDRESS or curr_state = RECEIVING or curr_state = TRANSMITTING else '0'; + + next_data_position <= 0 when start_condition_i = '1' else + 0 when stop_condition_i = '1' or curr_state = BUS_FREE else + (curr_data_position + 1) mod TRANSMIT_LEN when scl_pulse_i = '1' and communicating_with_master = '1' else + curr_data_position; + + generate_ack_o <= '1' when next_data_position = TRANSMIT_LEN - 1 and + (curr_state = BUS_ADDRESS or curr_state = RECEIVING) + else '0'; + expects_ack_o <= '1' when next_data_position = TRANSMIT_LEN - 1 and + (curr_state = TRANSMITTING) + else '0'; + + address_detect_start_o <= '1' when start_condition_i = '1' else '0'; + + receive_o <= '1' when curr_state = RECEIVING else '0'; + transmit_o <= '1' when curr_state = TRANSMITTING else '0'; + + start_receive_o <= '1' when curr_data_position /= 0 and next_data_position = 0 and curr_state = RECEIVING else '0'; + start_transmit_o <= '1' when curr_data_position /= 0 and next_data_position = 0 and curr_state = TRANSMITTING else '0'; + + next_state <= BUS_ADDRESS when start_condition_i = '1' else + -- BUS_BUSY when curr_state = BUS_FREE and (sda_i = '0' or scl_i = '0') else -- + -- assume busy when there is something on the bus? + BUS_FREE when stop_condition_i = '1' else + RECEIVING when curr_state = BUS_ADDRESS and address_detect_success_i = '1' and rw_i = '0' else + TRANSMITTING when curr_state = BUS_ADDRESS and address_detect_success_i = '1' and rw_i = '1' else + BUS_BUSY when curr_state = BUS_ADDRESS and address_detect_fail_i = '1' else + curr_state; + + set_regs: process (clk_i) is + begin -- process set_regs + if rising_edge(clk_i) then -- rising clock edge + if rst_in = '0' then -- synchronous reset (active low) + curr_state <= BUS_FREE; + curr_data_position <= 0; + else + curr_state <= next_state; + curr_data_position <= next_data_position; + end if; + end if; + end process set_regs; + +end architecture a1; -- 2.49.0