~ruther/vhdl-i2c

ref: 7118535deb1f07f92313e19e47e34c31f2e2ed92 vhdl-i2c/src/i2c/slave.vhd -rw-r--r-- 6.9 KiB
7118535d — Rutherther chore: add libs folder with vunit ignored 10 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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(6 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
    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;
    tx_clear_buffer_i : in  std_logic;

    -- errors
    err_noack_o  : out std_logic;
    err_sda_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
    waiting_o    : out std_logic;       -- Waiting for data or read data

    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, scl_falling : std_logic;

  signal transmitting, receiving : std_logic;

  signal tx_sda_enable : std_logic;
  signal tx_scl_stretch : std_logic;
  signal tx_noack, tx_unexpected_sda : std_logic;

  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_detect_store : std_logic;
  signal address_detection : std_logic;

  signal rw : std_logic;
  signal rst_i2c : 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;
  waiting_o <= tx_scl_stretch or rx_scl_stretch;

  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
    generic map (
      DELAY => SCL_FALLING_DELAY)
    port map (
      clk_i    => clk_i,
      rst_in   => rst_in,
      signal_i => scl_falling,
      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,
      falling_edge_o => scl_falling);

  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          => receiving,
      generate_ack_i        => generate_ack_i,
      rst_i2c_i             => rst_i2c,
      scl_rising           => scl_rising,
      scl_falling_delayed_i => scl_falling_delayed,
      scl_stretch_o         => rx_scl_stretch,
      sda_i                 => sync_sda,
      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,
      clear_buffer_i        => tx_clear_buffer_i,
      start_write_i         => transmitting,
      rst_i2c_i             => rst_i2c,
      scl_rising_i    => scl_rising,
      scl_falling_delayed_i => scl_falling_delayed,
      scl_stretch_o         => tx_scl_stretch,
      sda_i                 => sync_sda,
      sda_enable_o          => tx_sda_enable,
      unexpected_sda_o      => tx_unexpected_sda,
      noack_o               => tx_noack,
      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,
      store_address_i       => address_detect_store,
      scl_rising            => scl_rising,
      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,
      rst_i2c_o                => rst_i2c,
      start_condition_i        => start_condition,
      stop_condition_i         => stop_condition,
      err_noack_o              => err_noack_o,
      err_sda_o                => err_sda_o,
      unexpected_sda_i         => tx_unexpected_sda,
      expect_ack_i             => expect_ack_i,
      noack_i                  => tx_noack,
      rw_i                     => rw,
      address_detect_success_i => address_detect_success,
      address_detect_fail_i    => address_detect_fail,
      address_detect_start_o   => address_detect_activate,
      address_detect_store_o   => address_detect_store,
      address_detect_o         => address_detection,
      receive_o                => receiving,
      transmit_o               => transmitting,
      bus_busy_o               => bus_busy);

end architecture a1;
Do not follow this link