From a94d88d552d1e699670609f2edb7b81c439b99c4 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 30 Dec 2023 18:12:02 +0100 Subject: [PATCH] fix: make slave work --- src/i2c/address_detector.vhd | 16 ++- src/i2c/slave.vhd | 44 ++++--- src/i2c/slave_state.vhd | 2 + tb/i2c/address_detector_tb.vhd | 214 ++++++++++++++++++++++++--------- tb/i2c/rx_tb.vhd | 3 + 5 files changed, 201 insertions(+), 78 deletions(-) diff --git a/src/i2c/address_detector.vhd b/src/i2c/address_detector.vhd index 1dd6988..18723ea 100644 --- a/src/i2c/address_detector.vhd +++ b/src/i2c/address_detector.vhd @@ -10,6 +10,8 @@ entity address_detector is rst_in : in std_logic; -- Reset the detection address_i : in std_logic_vector(6 downto 0); scl_pulse_i : in std_logic; + scl_falling_delayed_i : in std_logic; + sda_enable_o : out std_logic; sda_i : in std_logic; -- The data that could contain the address start_i : in std_logic; -- When to start looking for the -- address. Will clear success_o @@ -23,7 +25,7 @@ entity address_detector is end entity address_detector; architecture a1 of address_detector is - type state_t is (IDLE, CHECKING_START, CHECKING, MATCH, FAIL); + type state_t is (IDLE, CHECKING_START, CHECKING, ACK, ACK_ON, MATCH, FAIL); signal curr_state : state_t; signal next_state : state_t; @@ -49,6 +51,8 @@ begin -- architecture a1 mismatch <= '1' when curr_index <= 6 and address_i(6 - curr_index) /= sda_i and scl_pulse_i = '1' else '0'; + sda_enable_o <= '1' when curr_state = ACK_ON else '0'; + set_next_state: process (all) is begin -- process set_next_state next_state <= curr_state; @@ -61,6 +65,16 @@ begin -- architecture a1 if mismatch = '1' then next_state <= FAIL; elsif curr_index = 7 and scl_pulse_i = '1' then + next_state <= ACK; + end if; + end if; + + if curr_state = ACK then + if scl_falling_delayed_i = '1' then + next_state <= ACK_ON; + end if; + elsif curr_state = ACK_ON then + if scl_falling_delayed_i = '1' then next_state <= MATCH; end if; end if; diff --git a/src/i2c/slave.vhd b/src/i2c/slave.vhd index 281ca63..039f103 100644 --- a/src/i2c/slave.vhd +++ b/src/i2c/slave.vhd @@ -12,7 +12,7 @@ entity slave is rst_in : in std_logic; -- Synchronous reset (active low) -- address - address_i : in std_logic_vector(7 downto 0); -- Address of the slave + address_i : in std_logic_vector(6 downto 0); -- Address of the slave generate_ack_i : in std_logic; expect_ack_i : in std_logic; @@ -20,12 +20,14 @@ entity slave is 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 + rx_stretch_i : in std_logic; -- 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 + tx_stretch_i : in std_logic; -- errors err_noack_o : out std_logic; @@ -49,7 +51,6 @@ architecture a1 of slave is 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; @@ -57,11 +58,14 @@ architecture a1 of slave is signal rx_sda_enable : std_logic; signal rx_scl_stretch : std_logic; + signal address_detect_sda_enable : 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 address_detection : std_logic; signal rw : std_logic; signal ss_condition : std_logic; @@ -73,12 +77,13 @@ begin -- architecture a1 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 + scl_enable_o <= tx_scl_stretch when transmitting = '1' and tx_stretch_i = '1' and scl_i = '0' else + rx_scl_stretch when receiving = '1' and rx_stretch_i = '1' and scl_i = '0' else '0'; sda_enable_o <= tx_sda_enable when transmitting = '1' else rx_sda_enable when receiving = '1' else + address_detect_sda_enable when address_detection = '1' else '0'; scl_falling_delayer: entity utils.delay @@ -122,7 +127,7 @@ begin -- architecture a1 port map ( clk_i => clk_i, rst_in => rst_in, - start_read_i => start_receive, + start_read_i => receiving, generate_ack_i => generate_ack_i, ss_condition_i => ss_condition, scl_pulse_i => scl_rising_pulse, @@ -140,7 +145,7 @@ begin -- architecture a1 port map ( clk_i => clk_i, rst_in => rst_in, - start_write_i => start_transmit, + start_write_i => transmitting, expect_ack_i => expect_ack_i, err_noack_o => err_noack_o, ss_condition_i => ss_condition, @@ -153,19 +158,21 @@ begin -- architecture a1 valid_i => tx_valid_i, write_data_i => tx_data_i); - address_detector: entity work.address_detector + 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 + clk_i => clk_i, + rst_in => rst_in, + address_i => address_i, + scl_pulse_i => scl_rising_pulse, + scl_falling_delayed_i => scl_falling_delayed, + sda_enable_o => address_detect_sda_enable, + 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, @@ -175,6 +182,7 @@ begin -- architecture a1 address_detect_success_i => address_detect_success, address_detect_fail_i => address_detect_fail, address_detect_start_o => address_detect_activate, + address_detect_o => address_detection, receive_o => receiving, transmit_o => transmitting, bus_busy_o => bus_busy); diff --git a/src/i2c/slave_state.vhd b/src/i2c/slave_state.vhd index aaa300f..b6bd16b 100644 --- a/src/i2c/slave_state.vhd +++ b/src/i2c/slave_state.vhd @@ -13,6 +13,7 @@ entity i2c_slave_state is address_detect_success_i : in std_logic; address_detect_fail_i : in std_logic; address_detect_start_o : out std_logic; + address_detect_o : out std_logic; receive_o : out std_logic; transmit_o : out std_logic; @@ -38,6 +39,7 @@ begin -- architecture a1 communicating_with_master <= '1' when curr_state = BUS_ADDRESS or curr_state = RECEIVING or curr_state = TRANSMITTING else '0'; address_detect_start_o <= '1' when start_condition_i = '1' else '0'; + address_detect_o <= '1' when curr_state = BUS_ADDRESS else '0'; receive_o <= '1' when curr_state = RECEIVING else '0'; transmit_o <= '1' when curr_state = TRANSMITTING else '0'; diff --git a/tb/i2c/address_detector_tb.vhd b/tb/i2c/address_detector_tb.vhd index a3e7345..e72cdcc 100644 --- a/tb/i2c/address_detector_tb.vhd +++ b/tb/i2c/address_detector_tb.vhd @@ -19,16 +19,23 @@ architecture tb of address_detector_tb is signal rst_n : std_logic := '0'; - signal scl_pulse : std_logic; + signal scl_pulse : std_logic := '0'; + signal scl_falling_pulse : std_logic := '0'; signal sda : std_logic; + signal scl : std_logic := '0'; signal start : std_logic; signal address : std_logic_vector(6 downto 0); signal success, fail, rw : std_logic; + signal sda_enable : std_logic; + shared variable trigger_scl_pulse : std_logic := '0'; + signal triggered_scl_pulse : std_logic := '0'; shared variable trigger_start : std_logic := '0'; + + signal one : std_logic := '1'; begin -- architecture tb clk <= not clk after CLK_PERIOD / 2; @@ -36,25 +43,38 @@ begin -- architecture tb uut : entity i2c.address_detector port map ( - clk_i => clk, - rst_in => rst_n, - address_i => address, - scl_pulse_i => scl_pulse, - sda_i => sda, - start_i => start, - rw_o => rw, - success_o => success, - fail_o => fail); + clk_i => clk, + rst_in => rst_n, + address_i => address, + scl_pulse_i => scl_pulse, + scl_falling_delayed_i => scl_falling_pulse, + sda_i => sda, + sda_enable_o => sda_enable, + start_i => start, + rw_o => rw, + success_o => success, + fail_o => fail); do_trigger_scl_pulse: process is begin -- process trigger_scl_pulse wait until rising_edge(clk); if trigger_scl_pulse = '1' then scl_pulse <= '1'; + scl_falling_pulse <= '0'; wait until rising_edge(clk); - wait for 0 ns; scl_pulse <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + scl_falling_pulse <= '1'; + wait until rising_edge(clk); + scl_falling_pulse <= '0'; trigger_scl_pulse := '0'; + + wait until rising_edge(clk); + + triggered_scl_pulse <= '1'; + wait for 0 ns; + triggered_scl_pulse <= '0'; end if; end process do_trigger_scl_pulse; @@ -87,54 +107,72 @@ begin -- architecture tb trigger_start := '1'; wait for 0 ns; wait until falling_edge(start); + report "ah"; sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= 'X'; -- rw trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + + + check_equal(sda_enable, '1'); + trigger_scl_pulse := '1'; + check_equal(success, '0'); + check_equal(fail, '0'); + wait until rising_edge(triggered_scl_pulse); + + wait until falling_edge(clk); + check_equal(sda_enable, '0'); check_equal(success, '1'); check_equal(fail, '0'); @@ -148,29 +186,45 @@ begin -- architecture tb wait until falling_edge(start); sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; -- rw trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + check_equal(sda_enable, '1'); -- ack + trigger_scl_pulse := '1'; + check_equal(success, '0'); + check_equal(fail, '0'); + wait until rising_edge(triggered_scl_pulse); + + + check_equal(success, '1'); + check_equal(fail, '0'); check_equal(rw, '1'); elsif run("write") then address <= "1100011"; @@ -181,29 +235,46 @@ begin -- architecture tb wait until falling_edge(start); sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; -- rw trigger_scl_pulse := '1'; - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + + check_equal(sda_enable, '1'); -- ack + trigger_scl_pulse := '1'; + check_equal(success, '0'); + check_equal(fail, '0'); + wait until rising_edge(triggered_scl_pulse); + + + check_equal(success, '1'); + check_equal(fail, '0'); check_equal(rw, '0'); elsif run("not_matching") then address <= "1110011"; @@ -216,42 +287,50 @@ begin -- architecture tb trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; -- rw trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + check_equal(success, '0'); check_equal(fail, '1'); @@ -266,42 +345,50 @@ begin -- architecture tb trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; -- rw trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '1'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + check_equal(success, '0'); check_equal(fail, '1'); @@ -321,49 +408,57 @@ begin -- architecture tb trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); sda <= '0'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); sda <= '1'; trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); sda <= 'X'; -- rw trigger_scl_pulse := '1'; check_equal(success, '0'); check_equal(fail, '0'); - wait until falling_edge(scl_pulse); + wait until rising_edge(triggered_scl_pulse); + + check_equal(sda_enable, '1'); -- ack + trigger_scl_pulse := '1'; + check_equal(success, '0'); + check_equal(fail, '0'); + wait until rising_edge(triggered_scl_pulse); check_equal(success, '1'); check_equal(fail, '0'); @@ -373,4 +468,5 @@ begin -- architecture tb test_runner_cleanup(runner); end process main; + stability_check: check_stable(clk, one, scl_pulse, scl_falling_pulse, sda_enable); end architecture tb; diff --git a/tb/i2c/rx_tb.vhd b/tb/i2c/rx_tb.vhd index 18046f3..2683c02 100644 --- a/tb/i2c/rx_tb.vhd +++ b/tb/i2c/rx_tb.vhd @@ -30,6 +30,8 @@ architecture a1 of rx_tb is signal confirm_read : std_logic := '0'; signal read_data : std_logic_vector(7 downto 0); + signal one : std_logic := '1'; + procedure trigger_scl_pulse( signal scl_rising_pulse : inout std_logic; signal scl_falling_pulse : inout std_logic) is @@ -199,4 +201,5 @@ begin -- architecture a1 test_runner_cleanup(runner); end process; + stability_check: check_stable(clk, one, scl_rising_pulse, scl_falling_pulse, sda_enable); end architecture a1; -- 2.48.1