~ruther/vhdl-i2c

ref: da60d1f13356b798f9fc9a7b734c9f81ec1187b7 vhdl-i2c/src/i2c/address_generator.vhd -rw-r--r-- 3.3 KiB
da60d1f1 — Rutherther tests: add startstop condition generator testbench 1 year, 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
library ieee;
use ieee.std_logic_1164.all;

use work.i2c_pkg.all;

entity address_generator is

  port (
    clk_i                 : in  std_logic;  -- Clock
    rst_in                : in  std_logic;  -- Synchronous reset (active low)
    address_i             : in  std_logic_vector(6 downto 0);
    rw_i                  : in  std_logic;  -- Read (not write)
    start_i               : in  std_logic;  -- When to start sending the address.
                                            -- A pulse. Every time it's '1',
                                        -- address will be sent from beginning
                                        -- First bit on rising edge
    scl_rising_i          : in  std_logic;
    scl_falling_delayed_i : in  std_logic;
    sda_enable_o          : out std_logic;  -- Data of the address to send.
    sda_i                 : out std_logic;
    noack_o               : out std_logic;
    unexpected_sda_o      : out std_logic;
    done_o                : out std_logic);
end entity address_generator;

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

  signal curr_index : integer range 0 to 8;
  signal next_index : integer range 0 to 8;

  signal curr_scl : std_logic;
  signal next_scl : std_logic;
begin  -- architecture a1

  sda_enable_o <= not address_i(6 - curr_index) when curr_index <= 6 and curr_state = GEN else
                  not rw_i when curr_index = 7 and curr_state = GEN else
                  '0';

  next_index <= 0 when start_i = '1' else
                curr_index + 1 when curr_index < 8 and scl_falling_delayed_i = '1' and curr_state = GEN else
                curr_index;

  unexpected_sda_o <= '1' when curr_state = GEN 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;

  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
      if start_i = '1' then
        start_gen := '1';
      end if;
    elsif curr_state = WAITING_FOR_FALLING then
      if scl_falling_delayed_i = '1' then
        next_state <= GEN;
      end if;
    elsif curr_state = GEN then
      if curr_index = 8 then
        next_state <= ACK;
      end if;
    elsif curr_state = ACK and scl_rising_i = '1' then
      next_state <= DONE;
    end if;

    if start_gen = '1' then
      if curr_scl = '1' then
        next_state <= WAITING_FOR_FALLING;
      else
        next_state <= GEN;
      end if;
    end if;
  end process set_next_state;

  set_regs: process (clk_i) is
  begin  -- process set_next
    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_scl <= '1';
      else
        curr_state <= next_state;
        curr_index <= next_index;
        curr_scl <= next_scl;
      end if;
    end if;
  end process set_regs;

end architecture a1;
Do not follow this link