~ruther/vhdl-i2c

01263b874ce8d9b39914f57dd58bf2329428a2e7 — Rutherther 1 year, 3 months ago 7ff1d12
fix: move to bus busy on arbitration err or start condition
2 files changed, 57 insertions(+), 7 deletions(-)

M src/i2c/master_state.vhd
M tb/i2c/master_tb.vhd
M src/i2c/master_state.vhd => src/i2c/master_state.vhd +12 -7
@@ 94,7 94,8 @@ begin  -- architecture a1
  any_err <= curr_err_arbitration or curr_err_noack_data or curr_err_noack_address or curr_err_general;
  any_terminal_err <= curr_err_noack_data or curr_err_noack_address or curr_err_general;
  control_over_bus <= '1' when curr_state /= IDLE and curr_state /= BUS_BUSY else '0';
  can_gen_cond <= '1' when curr_state = IDLE or ((curr_state = TRANSMITTING or curr_state = RECEIVING) and (waiting_for_data_i = '1' or tx_done_i = '1' or rx_done_i = '1')) else '0';
  can_gen_cond <= '1' when (curr_state = IDLE and start_condition_i = '0' and stop_condition_i = '0') or
                           ((curr_state = TRANSMITTING or curr_state = RECEIVING) and (waiting_for_data_i = '1' or tx_done_i = '1' or rx_done_i = '1')) else '0';

  req_scl_continuous_o <= '1' when curr_state = GENERATING_ADDRESS or
                          curr_state = TRANSMITTING or curr_state = RECEIVING else '0';


@@ 161,9 162,9 @@ begin  -- architecture a1
    next_state <= curr_state;

    if curr_state = IDLE then
      -- not much to do,
      -- condition for start
      -- is at the end
      if start_condition_i = '1' then
        next_state <= BUS_BUSY;
      end if;
    elsif curr_state = GENERATING_START then
      if start_condition_i = '1' then
        next_state <= GENERATED_START;


@@ 178,7 179,7 @@ begin  -- architecture a1
      elsif req_cond_done_i = '1' then
        next_state <= GENERATING_ADDRESS;
      elsif condition_early_i = '1' then
        next_state <= IDLE;
        next_state <= BUS_BUSY;
      end if;
    elsif curr_state = GENERATING_ADDRESS then
      if any_terminal_err = '1' then


@@ 219,6 220,10 @@ begin  -- architecture a1
      -- This state should not be possible
      -- if the components in i2c master are
      -- behaving correctly
    elsif curr_state = BUS_BUSY then
      if stop_condition_i = '1' then
        next_state <= IDLE;
      end if;
    end if;

    if can_gen_cond = '1' then


@@ 233,8 238,8 @@ begin  -- architecture a1
      end if;
    end if;

    if curr_err_arbitration = '1' then
      next_state <= IDLE;
    if curr_err_arbitration = '1' and (curr_state = GENERATING_ADDRESS or curr_state = TRANSMITTING) then
      next_state <= BUS_BUSY;
    end if;
  end process set_next_state;


M tb/i2c/master_tb.vhd => tb/i2c/master_tb.vhd +45 -0
@@ 309,6 309,51 @@ begin  -- architecture tb
        check_errors(exp_noack_data => '1');
        i2c_slave_check_stop(TIMEOUT, scl, sda);
        check_errors(exp_noack_data => '1');
      elsif run("bus_busy") then
        check_equal(bus_busy, '0');
        check_equal(dev_busy, '0');
        i2c_master_start("0000000", '0', scl, sda, exp_ack => '0');
        check_equal(bus_busy, '1', "Bus busy wrong.");
        check_equal(dev_busy, '0');
        i2c_master_stop(scl, sda);
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        check_equal(bus_busy, '0');
        check_equal(dev_busy, '0');
        check_errors;
      elsif run("bus_busy_start_request") then
        check_equal(bus_busy, '0');
        check_equal(dev_busy, '0');
        i2c_master_start("0000000", '0', scl, sda, exp_ack => '0');
        request_start("1111100", '0');
        check_equal(bus_busy, '1', "Bus busy wrong.");
        check_equal(dev_busy, '0');
        i2c_master_stop(scl, sda);      -- give bus away
        i2c_slave_check_start("1111100", '0', TIMEOUT, scl, sda);
        check_errors;
      elsif run("arbitration_lost_start_request") then
        check_equal(bus_busy, '0');
        check_equal(dev_busy, '0');

        request_start("1110101", '1');
        i2c_master_start("0000000", '1', scl, sda, exp_ack => '0');

        check_errors(exp_arbitration => '1');
        check_equal(bus_busy, '1', "Bus busy wrong.");
        check_equal(dev_busy, '0');

        request_start("1110101", '1', stop => '1');

        i2c_master_transmit("11111111", scl, sda, exp_ack => '0');
        i2c_master_stop(scl, sda);      -- give bus away
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        check_errors(exp_arbitration => '1');

        i2c_slave_check_start("1110101", '1', TIMEOUT, scl, sda);
        i2c_slave_transmit("11111111", TIMEOUT, scl, sda);
        i2c_slave_check_stop(TIMEOUT, scl, sda);
        rx_read_data("11111111", rx_confirm);
      end if;
    end loop;


Do not follow this link