~ruther/vhdl-i2c

a94d88d552d1e699670609f2edb7b81c439b99c4 — Rutherther 1 year, 3 months ago 068391c
fix: make slave work
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;

Do not follow this link