M src/i2c/address_detector.vhd => src/i2c/address_detector.vhd +15 -1
@@ 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;
M src/i2c/slave.vhd => src/i2c/slave.vhd +26 -18
@@ 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);
M src/i2c/slave_state.vhd => src/i2c/slave_state.vhd +2 -0
@@ 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';
M tb/i2c/address_detector_tb.vhd => tb/i2c/address_detector_tb.vhd +155 -59
@@ 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;
M tb/i2c/rx_tb.vhd => tb/i2c/rx_tb.vhd +3 -0
@@ 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;