~ruther/vhdl-i2c

68fab355c8db62ec484c95d0e90f2ac6de035ed8 — Rutherther 1 year, 5 months ago ac3b7a6
feat: add i2c misc entities
2 files changed, 128 insertions(+), 0 deletions(-)

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

use work.i2c_pkg.all;

entity address_detector is

  port (
    clk_i       : in  std_logic;        -- Input clock
    rst_in      : in  std_logic;        -- Reset the detection
    address_i   : in  std_logic_vector(6 downto 0);
    scl_pulse_i : in  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
    rw_o        : out std_logic;
    success_o   : out std_logic;        -- Whether full address matches
    fail_o      : out std_logic);       -- Whether matching failed. Will stay 0
                                        -- as long as bits are matching. Will
                                        -- be set to 1 the first bit that does
                                        -- not match the address

end entity address_detector;

architecture a1 of address_detector is
  type state_t is (IDLE, CHECKING_START, CHECKING, MATCH, FAIL);
  signal curr_state : state_t;
  signal next_state : state_t;

  signal curr_index : natural range 0 to 7;
  signal next_index : natural range 0 to 7;

  signal curr_read_rw : std_logic;
  signal next_read_rw : std_logic;

  signal mismatch : std_logic;
begin  -- architecture a1

  fail_o <= '1' when curr_state = FAIL else '0';
  success_o <= '1' when curr_state = MATCH else '0';
  rw_o <= curr_read_rw when curr_state = MATCH else '0';

  next_read_rw <= sda_i when scl_pulse_i = '1' and curr_index = 7 else
                  curr_read_rw;

  next_index <= (curr_index + 1) when curr_state = CHECKING and scl_pulse_i = '1' and curr_index < 7 else
                0;

  mismatch <= '1' when address_i(6 - curr_index) /= sda_i and curr_index <= 6 and scl_pulse_i = '1' else '0';

  set_next_state: process (start_i, curr_state, mismatch, scl_pulse_i) is
  begin  -- process set_next_state
    next_state <= curr_state;

    if curr_state = CHECKING_START then
      next_state <= CHECKING;
    end if;

    if curr_state = CHECKING then
      if mismatch = '1' then
        next_state <= FAIL;
      elsif curr_index = 7 and scl_pulse_i = '1' then
        next_state <= MATCH;
      end if;
    end if;

    if start_i = '1' then
      next_state <= CHECKING_START;
    end if;
  end process set_next_state;

  set_regs: process (clk_i) is
  begin  -- process set_regs
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        curr_state <= IDLE;
        curr_index <= 0;
        curr_read_rw <= '0';
      else
        curr_state <= next_state;
        curr_index <= next_index;
        curr_read_rw <= next_read_rw;
      end if;
    end if;
  end process set_regs;

end architecture a1;

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

entity startstop_condition_detector is

  port (
    clk_i   : in  std_logic;
    sda_i   : in  std_logic;
    scl_i   : in  std_logic;
    start_o : out std_logic;
    stop_o  : out std_logic);

end entity startstop_condition_detector;

architecture a1 of startstop_condition_detector is
  signal reg_start, reg_stop : std_logic;
  signal next_start, next_stop : std_logic;

  signal reg_prev_sda : std_logic;
  signal next_prev_sda : std_logic;
begin  -- architecture a1

  next_prev_sda <= sda_i;

  next_start <= '0' when reg_start = '1' else
                '1' when reg_prev_sda = '0' and sda_i = '1' and scl_i = '1' else
                '0';
  next_stop <= '0' when reg_stop = '1' else
               '1' when reg_prev_sda = '1' and sda_i = '0' and scl_i = '1' else
               '0';

  set_next: process (clk_i) is
  begin  -- process set_next
    if rising_edge(clk_i) then          -- rising clock edge
      reg_prev_sda <= next_prev_sda;
      reg_start <= next_start;
      reg_stop <= next_stop;
    end if;
  end process set_next;

end architecture a1;

Do not follow this link