From 068391c6bc2692b546faaabffcd4dcc2e0a5aed8 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 30 Dec 2023 11:41:03 +0100 Subject: [PATCH] feat: add slave top --- src/i2c/slave.vhd | 182 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 src/i2c/slave.vhd diff --git a/src/i2c/slave.vhd b/src/i2c/slave.vhd new file mode 100644 index 0000000..281ca63 --- /dev/null +++ b/src/i2c/slave.vhd @@ -0,0 +1,182 @@ +library ieee; +use ieee.std_logic_1164.all; + +library utils; + +entity slave is + generic ( + SCL_FALLING_DELAY : natural := 5); + + port ( + clk_i : in std_logic; -- Synchronous clock + rst_in : in std_logic; -- Synchronous reset (active low) + + -- address + address_i : in std_logic_vector(7 downto 0); -- Address of the slave + generate_ack_i : in std_logic; + expect_ack_i : in std_logic; + + -- rx + rx_valid_o : out std_logic; -- Data in rx_data are valid + rx_data_o : out std_logic_vector(7 downto 0); -- Received data + rx_confirm_i : in std_logic; -- Confirm data from rx_data are read + + -- tx + tx_ready_o : out std_logic; -- Transmitter ready for new data + tx_valid_i : in std_logic; -- Are data in tx_data valid? Should be + -- a pulse for one cycle only + tx_data_i : in std_logic_vector(7 downto 0); -- Data to transmit + + -- errors + err_noack_o : out std_logic; + + -- state + rw_o : out std_logic; -- 1 - read, 0 - write + dev_busy_o : out std_logic; -- Communicating with master + bus_busy_o : out std_logic; -- Bus is busy, someone else is communicating + + sda_i : in std_logic; -- I2C SDA line + scl_i : in std_logic; -- I2C SCL line + + sda_enable_o : out std_logic; -- Pull down sda + scl_enable_o : out std_logic); -- Pull down scl + +end entity slave; + +architecture a1 of slave is + signal sync_sda, sync_scl : std_logic; + signal start_condition, stop_condition : std_logic; + signal scl_rising_pulse, scl_falling_pulse : std_logic; + + signal transmitting, receiving : std_logic; + signal start_transmit, start_receive : std_logic; + + signal tx_sda_enable : std_logic; + signal tx_scl_stretch : std_logic; + + signal rx_sda_enable : std_logic; + signal rx_scl_stretch : std_logic; + + signal bus_busy : std_logic; + + signal address_detect_activate : std_logic; + signal address_detect_success : std_logic; + signal address_detect_fail : std_logic; + + signal rw : std_logic; + signal ss_condition : std_logic; + + signal scl_falling_delayed : std_logic; +begin -- architecture a1 + rw_o <= rw; + dev_busy_o <= transmitting or receiving; + bus_busy_o <= bus_busy; + ss_condition <= start_condition or stop_condition; + + scl_enable_o <= tx_scl_stretch when transmitting = '1' else + rx_scl_stretch when receiving = '1' else + '0'; + + sda_enable_o <= tx_sda_enable when transmitting = '1' else + rx_sda_enable when receiving = '1' else + '0'; + + scl_falling_delayer: entity utils.delay + generic map ( + DELAY => SCL_FALLING_DELAY) + port map ( + clk_i => clk_i, + rst_in => rst_in, + signal_i => scl_falling_pulse, + signal_o => scl_falling_delayed); + + scl_edge_detector: entity utils.sync_edge_detector + port map ( + clk_i => clk_i, + signal_i => sync_scl, + rising_edge_o => scl_rising_pulse, + falling_edge_o => scl_falling_pulse); + + sda_sync: entity utils.metastability_filter + port map ( + clk_i => clk_i, + signal_i => sda_i, + signal_o => sync_sda); + + scl_sync: entity utils.metastability_filter + port map ( + clk_i => clk_i, + signal_i => scl_i, + signal_o => sync_scl); + + condition_detector: entity work.startstop_condition_detector + port map ( + clk_i => clk_i, + sda_i => sync_sda, + scl_i => sync_scl, + start_o => start_condition, + stop_o => stop_condition); + + -- rx + rx: entity work.rx + port map ( + clk_i => clk_i, + rst_in => rst_in, + start_read_i => start_receive, + generate_ack_i => generate_ack_i, + ss_condition_i => ss_condition, + scl_pulse_i => scl_rising_pulse, + scl_falling_delayed_i => scl_falling_delayed, + scl_stretch_o => rx_scl_stretch, + sda_i => sda_i, + sda_enable_o => rx_sda_enable, + read_valid_o => rx_valid_o, + read_ready_o => open, + read_data_o => rx_data_o, + confirm_read_i => rx_confirm_i); + + -- tx + tx: entity work.tx + port map ( + clk_i => clk_i, + rst_in => rst_in, + start_write_i => start_transmit, + expect_ack_i => expect_ack_i, + err_noack_o => err_noack_o, + ss_condition_i => ss_condition, + scl_rising_pulse_i => scl_rising_pulse, + scl_falling_delayed_i => scl_falling_delayed, + scl_stretch_o => tx_scl_stretch, + sda_i => sda_i, + sda_enable_o => tx_sda_enable, + ready_o => tx_ready_o, + valid_i => tx_valid_i, + write_data_i => tx_data_i); + + address_detector: entity work.address_detector + port map ( + clk_i => clk_i, + rst_in => rst_in, + address_i => address_i, + scl_pulse_i => scl_rising_pulse, + sda_i => sync_sda, + start_i => address_detect_activate, + rw_o => rw, + success_o => address_detect_success, + fail_o => address_detect_fail); + + state_machine: entity work.i2c_slave_state + port map ( + clk_i => clk_i, + rst_in => rst_in, + start_condition_i => start_condition, + stop_condition_i => stop_condition, + rw_i => rw, + address_detect_success_i => address_detect_success, + address_detect_fail_i => address_detect_fail, + address_detect_start_o => address_detect_activate, + receive_o => receiving, + transmit_o => transmitting, + bus_busy_o => bus_busy); + +end architecture a1; -- 2.48.1