~ruther/vhdl-i2c

068391c6bc2692b546faaabffcd4dcc2e0a5aed8 — Rutherther 1 year, 3 months ago d2d01a3
feat: add slave top
1 files changed, 182 insertions(+), 0 deletions(-)

A src/i2c/slave.vhd
A src/i2c/slave.vhd => src/i2c/slave.vhd +182 -0
@@ 0,0 1,182 @@
library ieee;
use ieee.std_logic_1164.all;

library utils;

entity slave is
  generic (
    SCL_FALLING_DELAY : natural := 5);

  port (
    clk_i        : in std_logic;        -- Synchronous clock
    rst_in       : in std_logic;        -- Synchronous reset (active low)

    -- address
    address_i      : in std_logic_vector(7 downto 0);  -- Address of the slave
    generate_ack_i : in std_logic;
    expect_ack_i   : in std_logic;

    -- rx
    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

    -- 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

    -- errors
    err_noack_o  : out std_logic;

    -- state
    rw_o         : out std_logic;       -- 1 - read, 0 - write
    dev_busy_o   : out std_logic;       -- Communicating with master
    bus_busy_o   : out std_logic;       -- Bus is busy, someone else is communicating

    sda_i        : in std_logic;        -- I2C SDA line
    scl_i        : in std_logic;        -- I2C SCL line

    sda_enable_o : out std_logic;       -- Pull down sda
    scl_enable_o : out std_logic);      -- Pull down scl

end entity slave;

architecture a1 of slave is
  signal sync_sda, sync_scl                  : std_logic;
  signal start_condition, stop_condition     : std_logic;
  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;

  signal rx_sda_enable : std_logic;
  signal rx_scl_stretch : 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 rw : std_logic;
  signal ss_condition : 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' else
                  rx_scl_stretch when receiving = '1' else
                  '0';

  sda_enable_o <= tx_sda_enable when transmitting = '1' else
                  rx_sda_enable when receiving = '1' else
                  '0';

  scl_falling_delayer: entity utils.delay
    generic map (
      DELAY => SCL_FALLING_DELAY)
    port map (
      clk_i    => clk_i,
      rst_in   => rst_in,
      signal_i => scl_falling_pulse,
      signal_o => scl_falling_delayed);

  scl_edge_detector: entity utils.sync_edge_detector
    port map (
      clk_i          => clk_i,
      signal_i       => sync_scl,
      rising_edge_o  => scl_rising_pulse,
      falling_edge_o => scl_falling_pulse);

  sda_sync: entity utils.metastability_filter
    port map (
      clk_i    => clk_i,
      signal_i => sda_i,
      signal_o => sync_sda);

  scl_sync: entity utils.metastability_filter
    port map (
      clk_i    => clk_i,
      signal_i => scl_i,
      signal_o => sync_scl);

  condition_detector: entity work.startstop_condition_detector
    port map (
      clk_i  => clk_i,
      sda_i   => sync_sda,
      scl_i   => sync_scl,
      start_o => start_condition,
      stop_o  => stop_condition);

  -- rx
  rx: entity work.rx
    port map (
      clk_i                 => clk_i,
      rst_in                => rst_in,
      start_read_i          => start_receive,
      generate_ack_i        => generate_ack_i,
      ss_condition_i        => ss_condition,
      scl_pulse_i           => scl_rising_pulse,
      scl_falling_delayed_i => scl_falling_delayed,
      scl_stretch_o         => rx_scl_stretch,
      sda_i                 => sda_i,
      sda_enable_o          => rx_sda_enable,
      read_valid_o          => rx_valid_o,
      read_ready_o          => open,
      read_data_o           => rx_data_o,
      confirm_read_i        => rx_confirm_i);

  -- tx
  tx: entity work.tx
    port map (
      clk_i                 => clk_i,
      rst_in                => rst_in,
      start_write_i         => start_transmit,
      expect_ack_i          => expect_ack_i,
      err_noack_o           => err_noack_o,
      ss_condition_i        => ss_condition,
      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,
      ready_o               => tx_ready_o,
      valid_i               => tx_valid_i,
      write_data_i          => tx_data_i);

  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
    port map (
      clk_i                    => clk_i,
      rst_in                   => rst_in,
      start_condition_i        => start_condition,
      stop_condition_i         => stop_condition,
      rw_i                     => rw,
      address_detect_success_i => address_detect_success,
      address_detect_fail_i    => address_detect_fail,
      address_detect_start_o   => address_detect_activate,
      receive_o                => receiving,
      transmit_o               => transmitting,
      bus_busy_o               => bus_busy);

end architecture a1;

Do not follow this link