M src/i2c/rx.vhd => src/i2c/rx.vhd +2 -2
@@ 24,7 24,7 @@ entity rx is
clk_i : in std_logic; -- Clock
rst_in : in std_logic; -- Reset (asynchronous)
start_read_i : in std_logic; -- Start reading with next scl_pulse
- ss_condition_i : in std_logic; -- Reset rx circuitry
+ rst_i2c_i : in std_logic; -- Reset rx circuitry
scl_pulse_i : in std_logic; -- SCL rising edge pulse
scl_falling_delayed_i : in std_logic; -- SCL rising edge pulse
@@ 125,7 125,7 @@ begin -- architecture a1
end if;
end if;
- if ss_condition_i = '1' then
+ if rst_i2c_i = '1' then
next_state <= IDLE;
end if;
end process set_next_state;
M src/i2c/slave.vhd => src/i2c/slave.vhd +14 -10
@@ 32,6 32,7 @@ entity slave is
-- errors
err_noack_o : out std_logic;
+ err_sda_o : out std_logic;
-- state
rw_o : out std_logic; -- 1 - read, 0 - write
@@ 55,6 56,7 @@ architecture a1 of slave is
signal tx_sda_enable : std_logic;
signal tx_scl_stretch : std_logic;
+ signal tx_noack, tx_unexpected_sda : std_logic;
signal rx_sda_enable : std_logic;
signal rx_scl_stretch : std_logic;
@@ 69,14 71,13 @@ architecture a1 of slave is
signal address_detection : std_logic;
signal rw : std_logic;
- signal ss_condition : std_logic;
+ signal rst_i2c : 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' 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
@@ 124,13 125,13 @@ begin -- architecture a1
stop_o => stop_condition);
-- rx
- rx: entity work.rx
+ rx : entity work.rx
port map (
clk_i => clk_i,
rst_in => rst_in,
start_read_i => receiving,
generate_ack_i => generate_ack_i,
- ss_condition_i => ss_condition,
+ rst_i2c_i => rst_i2c,
scl_pulse_i => scl_rising_pulse,
scl_falling_delayed_i => scl_falling_delayed,
scl_stretch_o => rx_scl_stretch,
@@ 148,17 149,14 @@ begin -- architecture a1
rst_in => rst_in,
clear_buffer_i => tx_clear_buffer_i,
start_write_i => transmitting,
- expect_ack_i => expect_ack_i,
- err_noack_o => err_noack_o,
- ss_condition_i => ss_condition,
+ rst_i2c_i => rst_i2c,
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,
- unexpected_sda_o => open, -- ignore in the slave, nothing to do?
- -- TODO output an error if unexpected
- -- level when transmitting
+ unexpected_sda_o => tx_unexpected_sda,
+ noack_o => tx_noack,
ready_o => tx_ready_o,
valid_i => tx_valid_i,
write_data_i => tx_data_i);
@@ 181,8 179,14 @@ begin -- architecture a1
port map (
clk_i => clk_i,
rst_in => rst_in,
+ rst_i2c_o => rst_i2c,
start_condition_i => start_condition,
stop_condition_i => stop_condition,
+ err_noack_o => err_noack_o,
+ err_sda_o => err_sda_o,
+ unexpected_sda_i => tx_unexpected_sda,
+ expect_ack_i => expect_ack_i,
+ noack_i => tx_noack,
rw_i => rw,
address_detect_success_i => address_detect_success,
address_detect_fail_i => address_detect_fail,
M src/i2c/slave_state.vhd => src/i2c/slave_state.vhd +34 -5
@@ 5,11 5,18 @@ entity i2c_slave_state is
port (
clk_i : in std_logic;
rst_in : in std_logic;
+ rst_i2c_o : out std_logic;
+
+ noack_i : in std_logic;
+ expect_ack_i : in std_logic;
+ unexpected_sda_i : in std_logic;
+ err_noack_o : out std_logic;
+ err_sda_o : out 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;
@@ 33,22 40,40 @@ architecture a1 of i2c_slave_state is
signal curr_state : slave_state := BUS_FREE;
signal next_state : slave_state;
+ signal curr_err_noack : std_logic;
+ signal next_err_noack : std_logic;
+
+ signal curr_err_sda : std_logic;
+ signal next_err_sda : std_logic;
+
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';
-
- address_detect_start_o <= '1' when start_condition_i = '1' else '0';
- address_detect_o <= '1' when curr_state = BUS_ADDRESS 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';
+ err_noack_o <= curr_err_noack;
+ err_sda_o <= curr_err_sda;
+ rst_i2c_o <= curr_err_noack or curr_err_sda or start_condition_i or stop_condition_i;
receive_o <= '1' when curr_state = RECEIVING else '0';
transmit_o <= '1' when curr_state = TRANSMITTING else '0';
bus_busy_o <= '1' when curr_state = BUS_BUSY else '0';
+ next_err_sda <= '0' when start_condition_i = '1' or stop_condition_i = '1' else
+ '1' when curr_err_sda = '1' else
+ '1' when unexpected_sda_i = '1' and curr_state = TRANSMITTING else
+ '0';
+
+ next_err_noack <= '0' when start_condition_i = '1' or stop_condition_i = '1' else
+ '1' when curr_err_noack = '1' else
+ '1' when noack_i = '1' and curr_state = TRANSMITTING and expect_ack_i = '1' 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
+ BUS_BUSY when next_err_sda = '1' or next_err_noack = '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
@@ 59,8 84,12 @@ begin -- architecture a1
if rising_edge(clk_i) then -- rising clock edge
if rst_in = '0' then -- synchronous reset (active low)
curr_state <= BUS_FREE;
+ curr_err_sda <= '0';
+ curr_err_noack <= '0';
else
curr_state <= next_state;
+ curr_err_noack <= next_err_noack;
+ curr_err_sda <= next_err_sda;
end if;
end if;
end process set_regs;
M src/i2c/tx.vhd => src/i2c/tx.vhd +6 -19
@@ 24,12 24,11 @@ entity tx is
clk_i : in std_logic;
rst_in : in std_logic;
start_write_i : in std_logic;
- ss_condition_i : in std_logic; -- Reset rx circuitry
+ rst_i2c_i : in std_logic; -- Reset rx circuitry
clear_buffer_i : in std_logic;
- expect_ack_i : in std_logic;
unexpected_sda_o : out std_logic;
- err_noack_o : out std_logic;
+ noack_o : out std_logic;
scl_rising_pulse_i : in std_logic;
scl_falling_delayed_i : in std_logic;
@@ 79,10 78,10 @@ architecture a1 of tx is
signal ready : std_logic;
begin -- architecture a1
scl_stretch_o <= '1' when curr_state = WAITING_FOR_DATA else '0';
- ready_o <= ready and not curr_err_noack;
+ 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) else '0';
- err_noack_o <= curr_err_noack;
+ unexpected_sda_o <= '1' when curr_state = SENDING and sda_i /= tx_buffer(8) and scl_rising_pulse_i = '1' else '0';
+ noack_o <= '1' when curr_state = ACK and sda_i = '1' and scl_rising_pulse_i = '1' else '0';
ready <= '0' when curr_tx_buffers_filled(curr_saving_buffer_index) = '1' or curr_err_noack = '1' else '1';
tx_buffer <= curr_tx_buffers(curr_tx_buffer_index);
@@ 98,11 97,6 @@ begin -- architecture a1
next_saving_buffer_index <= (curr_saving_buffer_index + 1) mod 2 when ready = '1' and valid_i = '1' else
curr_saving_buffer_index;
- next_err_noack <= '0' when expect_ack_i = '0' else
- '1' when curr_err_noack = '1' else
- '1' when curr_state = ACK and scl_rising_pulse_i = '1' and sda_i = '1' else
- '0';
-
set_next_tx_buffers: process(all) is
begin -- process set_next_tx_buffer
next_tx_buffers <= curr_tx_buffers;
@@ 172,10 166,6 @@ begin -- architecture a1
end if;
end if;
- if curr_err_noack = '1' then
- next_state <= IDLE; -- not doing anything after an error.
- -- Waiting for ss condition or reset
- end if;
end process set_next_state;
set_regs: process (clk_i) is
@@ 188,11 178,9 @@ begin -- architecture a1
curr_tx_buffers_filled <= "00";
curr_saving_buffer_index <= 0;
curr_scl <= '1'; -- assume 1 (the default, no one transmitting)
- curr_err_noack <= '0';
- elsif ss_condition_i = '1' then
+ elsif rst_i2c_i = '1' then
curr_state <= IDLE;
curr_scl <= '1'; -- assume 1 (the default, no one transmitting)
- curr_err_noack <= '0';
else
curr_state <= next_state;
curr_tx_buffers <= next_tx_buffers;
@@ 200,7 188,6 @@ begin -- architecture a1
curr_tx_buffers_filled <= next_tx_buffers_filled;
curr_saving_buffer_index <= next_saving_buffer_index;
curr_scl <= next_scl;
- curr_err_noack <= next_err_noack;
end if;
end if;
end process set_regs;
M tb/i2c/rx_tb.vhd => tb/i2c/rx_tb.vhd +1 -1
@@ 87,7 87,7 @@ begin -- architecture a1
port map (
clk_i => clk,
rst_in => rst_n,
- ss_condition_i => '0',
+ rst_i2c_i => '0',
generate_ack_i => '1',
start_read_i => start_read,
scl_pulse_i => scl_rising_pulse,
M tb/i2c/slave_tb.vhd => tb/i2c/slave_tb.vhd +38 -10
@@ 31,7 31,7 @@ architecture tb of slave_tb is
signal slave_scl : std_logic;
signal dev_busy, bus_busy : std_logic;
- signal err_noack : std_logic;
+ signal err_noack, err_sda : std_logic;
signal rw : std_logic;
signal rx_confirm : std_logic := '0';
@@ 78,14 78,15 @@ begin -- architecture tb
tx_stretch_i => '0',
tx_clear_buffer_i => '0',
- err_noack_o => err_noack,
- rw_o => rw,
- dev_busy_o => dev_busy,
- bus_busy_o => bus_busy,
- sda_i => slave_sda,
- scl_i => slave_scl,
- sda_enable_o => slave_sda_enable,
- scl_enable_o => slave_scl_enable);
+ err_noack_o => err_noack,
+ err_sda_o => err_sda,
+ rw_o => rw,
+ dev_busy_o => dev_busy,
+ bus_busy_o => bus_busy,
+ sda_i => slave_sda,
+ scl_i => slave_scl,
+ sda_enable_o => slave_sda_enable,
+ scl_enable_o => slave_scl_enable);
-- stable sda_enable when scl high
sda_stability_check: check_stable(clk, one, scl, not_scl, slave_sda_enable);
@@ 156,7 157,6 @@ begin -- architecture tb
i2c_master_receive("11010100", scl, sda, ack => '0');
check_equal(rw, '1');
- check_equal(dev_busy, '1');
check_equal(err_noack, '1');
@@ 164,6 164,34 @@ begin -- architecture tb
wait until falling_edge(clk);
wait until falling_edge(clk);
+ wait until falling_edge(clk);
+ check_equal(err_noack, '0');
+
+ wait until falling_edge(clk);
+ wait until falling_edge(clk);
+ check_equal(dev_busy, '0');
+ check_equal(bus_busy, '0');
+ elsif run("read_unexpected_sda") then
+ address <= "1100001";
+
+ i2c_master_start("1100001", '1', scl, sda);
+
+ tx_write_data("11010100", tx_data, tx_valid);
+
+ scl_fall(scl);
+ sda <= '0';
+
+ scl_rise(scl);
+
+ check_equal(err_sda, '1');
+
+ i2c_master_stop(scl, sda);
+
+ wait until falling_edge(clk);
+ wait until falling_edge(clk);
+ wait until falling_edge(clk);
+
+ check_equal(err_sda, '0');
check_equal(dev_busy, '0');
check_equal(bus_busy, '0');
elsif run("write_read") then
M tb/i2c/tb_i2c_master_pkg.vhd => tb/i2c/tb_i2c_master_pkg.vhd +5 -5
@@ 92,8 92,8 @@ package body tb_i2c_master_pkg is
procedure i2c_master_receive (
constant exp_data : in std_logic_vector(7 downto 0);
- signal scl : inout std_logic;
- signal sda : inout std_logic;
+ signal scl : inout std_logic;
+ signal sda : inout std_logic;
constant ack : in std_logic := '1';
constant stop_condition : in std_logic := '0') is
@@ 134,9 134,9 @@ package body tb_i2c_master_pkg is
procedure i2c_master_start (
constant address : in std_logic_vector(6 downto 0);
constant rw : in std_logic;
- signal scl : inout std_logic;
- signal sda : inout std_logic;
- constant exp_ack : in std_logic := '1') is
+ signal scl : inout std_logic;
+ signal sda : inout std_logic;
+ constant exp_ack : in std_logic := '1') is
begin
if scl = 'H' and sda = '0' then
scl_fall(scl);
M tb/i2c/tx_tb.vhd => tb/i2c/tx_tb.vhd +25 -8
@@ 31,12 31,15 @@ architecture a1 of tx_tb is
signal unexpected_sda : std_logic;
- signal err_noack : std_logic;
+ signal noack : std_logic;
signal validate_sda_stable_when_scl_high : std_logic := '0';
signal check_noerr : std_logic := '0';
signal zero : std_logic := '0';
+ signal curr_noack : std_logic;
+ signal next_noack : std_logic;
+
procedure trigger_scl_pulse(
signal scl : inout std_logic;
signal scl_rising_pulse : inout std_logic;
@@ 99,10 102,10 @@ architecture a1 of tx_tb is
end if;
for i in 7 downto 0 loop
- check_equal(sda_enable, not data(i));
+ check_equal(sda_enable, not data(i), "Unexpected sda enable");
if check_ready /= 'Z' then
- check_equal(ready, check_ready);
+ check_equal(ready, check_ready, "Unexpected ready");
end if;
check(scl_stretch = '0', "Cannot send when stretch is active", failure);
@@ 128,10 131,9 @@ begin -- architecture a1
clk_i => clk,
rst_in => rst_n,
start_write_i => start_write,
- ss_condition_i => '0',
- expect_ack_i => '1',
+ rst_i2c_i => '0',
clear_buffer_i => '0',
- err_noack_o => err_noack,
+ noack_o => noack,
scl_stretch_o => scl_stretch,
scl_rising_pulse_i => scl_rising_pulse,
scl_falling_delayed_i => scl_falling_pulse,
@@ 145,9 147,23 @@ begin -- architecture a1
clk <= not clk after CLK_PERIOD / 2;
rst_n <= '1' after 2 * CLK_PERIOD;
+
sda <= '0' when sda_override = '1' else
not sda_enable;
+ next_noack <= '1' when noack;
+
+ set_noack: process (clk) is
+ begin -- process set_noack
+ if rising_edge(clk) then -- rising clock edge
+ if rst_n = '0' then -- synchronous reset (active low)
+ curr_noack <= '0';
+ else
+ curr_noack <= next_noack;
+ end if;
+ end if;
+ end process set_noack;
+
main: process is
begin -- process
scl <= '1';
@@ 229,7 245,7 @@ begin -- architecture a1
valid <= '0';
check_noerr <= '0'; -- disable no err check
check_received_data("11010100", '1', '0', sda_override, scl, scl_rising_pulse, scl_falling_pulse);
- check_equal(err_noack, '1');
+ check_equal(curr_noack, '1');
check_equal(sda_enable, '0');
end if;
end loop;
@@ 237,6 253,7 @@ begin -- architecture a1
test_runner_cleanup(runner);
end process;
- no_err: check_stable(clk, check_noerr, check_noerr, zero, err_noack);
+ no_noack_err: check_stable(clk, check_noerr, check_noerr, zero, noack);
+ no_sda_unexpected_err: check_stable(clk, check_noerr, check_noerr, zero, unexpected_sda);
stability_check: check_stable(clk, validate_sda_stable_when_scl_high, scl_rising_pulse, scl_falling_pulse, sda_enable);
end architecture a1;