~ruther/vhdl-i2c

5c423e6c6b1f5ae648804750e0456fbb14c2becb — Rutherther 1 year, 5 months ago 7f5a4fb
fix: issues on master
M src/i2c/address_generator.vhd => src/i2c/address_generator.vhd +14 -5
@@ 22,7 22,7 @@ entity address_generator is
end entity address_generator;

architecture a1 of address_generator is
  type state_t is (IDLE, WAITING_FOR_FALLING, GEN, ACK, DONE);
  type state_t is (IDLE, WAITING_FOR_FALLING, GEN, ACK);
  signal curr_state : state_t;
  signal next_state : state_t;



@@ 31,6 31,9 @@ architecture a1 of address_generator is

  signal curr_scl : std_logic;
  signal next_scl : std_logic;

  signal curr_done : std_logic;
  signal next_done : std_logic;
begin  -- architecture a1

  sda_enable_o <= not address_i(6 - curr_index) when curr_index <= 6 and curr_state = GEN else


@@ 43,20 46,24 @@ begin  -- architecture a1

  unexpected_sda_o <= '1' when curr_state = GEN and curr_index <= 6 and sda_i /= address_i(6 - curr_index) and scl_rising_i = '1' else '0';
  noack_o <= '1' when curr_state = ACK and scl_rising_i = '1' and sda_i = '1' else '0';
  done_o <= '1' when curr_state = DONE else '0';

  next_scl <= '1' when scl_rising_i = '1' else
              '0' when scl_falling_delayed_i = '1' else
              curr_scl;

  done_o <= curr_done and not next_done;
  next_done <= '1' when curr_state = ACK and next_state /= ACK else
               '1' when curr_done = '1' and scl_falling_delayed_i = '0' else
               '0';

  set_next_state: process (all) is
    variable start_gen : std_logic;
  begin  -- process set_next_state
    next_state <= curr_state;
    start_gen := '0';

    if curr_state = IDLE then
    elsif curr_state = WAITING_FOR_FALLING then
    -- if curr_state = IDLE then
    if curr_state = WAITING_FOR_FALLING then
      if scl_falling_delayed_i = '1' then
        next_state <= GEN;
      end if;


@@ 65,7 72,7 @@ begin  -- architecture a1
        next_state <= ACK;
      end if;
    elsif curr_state = ACK and scl_rising_i = '1' then
      next_state <= DONE;
      next_state <= IDLE;
    end if;

    if start_i = '1' then


@@ 88,10 95,12 @@ begin  -- architecture a1
        curr_state <= IDLE;
        curr_index <= 0;
        curr_scl <= '1';
        curr_done <= '0';
      else
        curr_state <= next_state;
        curr_index <= next_index;
        curr_scl <= next_scl;
        curr_done <= next_done;
      end if;
    end if;
  end process set_regs;

M src/i2c/master.vhd => src/i2c/master.vhd +2 -2
@@ 5,8 5,8 @@ library utils;

entity master is
  generic (
    SCL_FALLING_DELAY : natural := 5;
    SCL_MIN_STABLE_CYCLES : natural := 10);
    SCL_FALLING_DELAY : natural;
    SCL_MIN_STABLE_CYCLES : natural);

  port (
    clk_i               : in  std_logic;  -- Synchronous clock

M src/i2c/master_state.vhd => src/i2c/master_state.vhd +9 -7
@@ 1,5 1,6 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity master_state is



@@ 91,7 92,7 @@ architecture a1 of master_state is
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;
  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';

  req_scl_continuous_o <= '1' when curr_state = GENERATING_ADDRESS or


@@ 119,12 120,12 @@ begin  -- architecture a1

  rst_i2c_o <= any_err or cond_gen;

  next_gen_start_req <= '1' when start_i = '1' and run_i = '1' else
                        '0' when curr_state = GENERATING_START else
  next_gen_start_req <= '0' when curr_state = GENERATING_START or curr_state = GENERATED_START else
                        '1' when start_i = '1' and run_i = '1' else
                        curr_gen_start_req;

  next_gen_stop_req <= '1' when stop_i = '1' else
                        '0' when curr_state = GENERATING_STOP else
  next_gen_stop_req <= '0' when curr_state = GENERATING_STOP or curr_state = GENERATED_STOP else
                       '1' when stop_i = '1' else
                        curr_gen_stop_req;

  next_err_general <= '0' when curr_state = GENERATING_START else


@@ 219,12 220,13 @@ begin  -- architecture a1
    end if;

    if can_gen_cond = '1' then
      if curr_gen_start_req = '1' then
      if curr_gen_start_req = '1' and curr_state /= GENERATING_START and curr_state /= GENERATED_START then
        next_state <= GENERATING_START;
       
        -- if no control over bus, do not
        -- allow generating stop condition
        -- TODO consider not checking that?
      elsif curr_gen_stop_req = '1' and control_over_bus = '1' then
      elsif curr_gen_stop_req = '1' and control_over_bus = '1' and curr_state /= GENERATING_STOP and curr_state /= GENERATED_STOP then
        next_state <= GENERATING_STOP;
      end if;
    end if;

M src/i2c/startstop_condition_generator.vhd => src/i2c/startstop_condition_generator.vhd +7 -0
@@ 1,5 1,6 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library utils;



@@ 105,6 106,8 @@ begin  -- architecture a1
      elsif curr_count = DELAY then
        next_state <= PREPARE_SDA;
        next_count_en <= '0';
      elsif curr_scl = '1' then
        next_count_en <= '0';
      end if;
    elsif curr_state = PREPARE_SDA then
      next_count_en <= '1';


@@ 124,6 127,8 @@ begin  -- architecture a1
      elsif curr_count = DELAY then
        next_state <= GEN_COND;
        next_count_en <= '0';
      elsif curr_scl = '1' then
        next_count_en <= '1';
      end if;
    elsif curr_state = GEN_COND then
      -- assume correct condition here. If it's the wrong one,


@@ 144,6 149,8 @@ begin  -- architecture a1
      elsif curr_count = DELAY then
        next_state <= DONE;
        next_count_en <= '0';
      elsif curr_scl = '0' then
        next_count_en <= '1';
      end if;
    elsif curr_state = DONE then
      next_count_en <= '0';

M src/mcu_slave/counter.vhd => src/mcu_slave/counter.vhd +6 -4
@@ 14,8 14,11 @@ entity counter is
  port (
    clk_i  : in std_logic;
    rst_i : in std_logic;
    rst_on : out std_logic;
    err_noack_o : out std_logic;
    err_noack_data_o : out std_logic;
    err_noack_address_o : out std_logic;
    err_arbitration_o : out std_logic;
    err_general_o : out std_logic;

    bus_busy_o : out std_logic;
    dev_busy_o : out std_logic;
    sda_io : inout std_logic;


@@ 40,7 43,6 @@ architecture a1 of counter is
  signal tx_data : std_logic_vector(7 downto 0);
begin
  rst_n <= not rst_sync;
  rst_on <= rst_n;

  sync_reset: entity utils.metastability_filter
    port map (


@@ 77,7 79,7 @@ begin
      tx_stretch_i   => '0',
      tx_clear_buffer_i => '0',

      err_noack_o    => err_noack_o,
      err_noack_o    => err_noack_data_o,
      rw_o           => open,
      dev_busy_o     => dev_busy_o,
      bus_busy_o     => bus_busy_o,

M tb/i2c/master_tb.vhd => tb/i2c/master_tb.vhd +34 -3
@@ 47,6 47,8 @@ architecture tb of master_tb is

  constant SCL_MIN_STABLE_CYCLES : natural := 10;
  constant TIMEOUT : time := SCL_MIN_STABLE_CYCLES * CLK_PERIOD * 2;

  signal stable_check : std_logic := '0';
begin  -- architecture tb

  clk <= not clk after CLK_PERIOD / 2;


@@ 106,6 108,9 @@ begin  -- architecture tb
  -- TODO ensure active only when no start/stop
  -- conditions should be generated...
  -- sda_stability_check: check_stable(clk, one, scl, not_scl, master_sda_enable);
  --
  sda_stable: check_stable(clk, stable_check, one, zero, master_sda);
  scl_stable: check_stable(clk, stable_check, one, zero, master_scl);

  main: process is
    procedure request_start(


@@ 195,7 200,7 @@ begin  -- architecture tb
        check_errors;
        i2c_slave_check_stop(TIMEOUT, scl, sda);
        check_errors;
      elsif run("waiting") then
      elsif run("waiting_write_tx") then
        request_start("1110101", '0');
        i2c_slave_check_start("1110101", '0', TIMEOUT, scl, sda);
        check_errors;


@@ 203,9 208,10 @@ begin  -- architecture tb
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        for i in 0 to 100 loop
          check_equal(waiting, '1');
          check_equal(scl, '0');
          check_equal(waiting, '1', "Waiting wrong");
          check_equal(scl, '0', "SCL wrong");
          wait until falling_edge(clk);
        end loop;  -- i



@@ 217,6 223,28 @@ begin  -- architecture tb
        check_errors;
        i2c_slave_check_stop(TIMEOUT, scl, sda);
        check_errors;
      elsif run("waiting_stop") then
        tx_write_data("00000000", tx_data, tx_valid);
        request_start("1110101", '0');
        i2c_slave_check_start("1110101", '0', TIMEOUT, scl, sda);
        i2c_slave_receive("00000000", 2 * TIMEOUT, scl, sda);
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        wait until falling_edge(clk);
        check_equal(waiting, '1');
        request_stop;
        check_errors;
        i2c_slave_check_stop(TIMEOUT, scl, sda);
        check_errors;

      elsif run("waiting_right_away_stop") then
        request_start("1110101", '0', stop => '1');
        i2c_slave_check_start("1110101", '0', TIMEOUT, scl, sda);
        check_errors;
        i2c_slave_check_stop(TIMEOUT, scl, sda);
        check_errors;

      elsif run("write_read") then
        tx_write_data("11101010", tx_data, tx_valid);
        tx_write_data("00001111", tx_data, tx_valid);


@@ 284,6 312,9 @@ begin  -- architecture tb
      end if;
    end loop;

    stable_check <= '1';
    wait for TIMEOUT * 10;

    test_runner_cleanup(runner);
  end process main;
end architecture tb;

M tb/i2c/tb_i2c_slave_pkg.vhd => tb/i2c/tb_i2c_slave_pkg.vhd +1 -1
@@ 116,7 116,7 @@ package body tb_i2c_slave_pkg is
      wait_for_scl_rise(scl_timeout, scl);
      if exp_data(i) = '1' then
        check(sda = '1' or sda = 'H', result("Received data (sda) not as expected."));
      else
      elsif exp_data(i) = '0' then
        check(sda = '0' or sda = 'L', result("Received data (sda) not as expected."));
      end if;
      wait_for_scl_fall(scl_timeout, scl);

M tb/mcu_slave/counter_tb.vhd => tb/mcu_slave/counter_tb.vhd +7 -8
@@ 38,14 38,13 @@ begin  -- architecture tb
    generic map (
      DELAY => 1)
    port map (
      clk_i       => clk,
      rst_i       => rst,
      rst_on      => open,
      err_noack_o => err_noack,
      dev_busy_o  => dev_busy,
      bus_busy_o  => bus_busy,
      sda_io      => sda,
      scl_io      => scl
      clk_i            => clk,
      rst_i            => rst,
      err_noack_data_o => err_noack,
      dev_busy_o       => dev_busy,
      bus_busy_o       => bus_busy,
      sda_io           => sda,
      scl_io           => scl
    );

  -- pull up

Do not follow this link