~ruther/vhdl-i2c

ref: 7118535deb1f07f92313e19e47e34c31f2e2ed92 vhdl-i2c/src/i2c/master_state.vhd -rw-r--r-- 10.5 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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity master_state is

  port (
    clk_i                    : in  std_logic;
    rst_in                   : in  std_logic;
    rst_i2c_o                : out std_logic;
-- control interface
    start_i                  : in  std_logic;
    stop_i                   : in  std_logic;
    run_i                    : in  std_logic;
    rw_i                     : in  std_logic;
-- error inputs and config
    expect_ack_i             : in  std_logic;
    noack_address_i          : in  std_logic;
    noack_data_i             : in  std_logic;
    unexpected_sda_address_i : in  std_logic;
    unexpected_sda_data_i    : in  std_logic;
    condition_early_i        : in std_logic;
-- error outputs (reset on new run)
    err_noack_address_o      : out std_logic;
    err_noack_data_o         : out std_logic;
    err_arbitration_o        : out std_logic;
    err_general_o            : out std_logic;
-- i2c condition detection
    start_condition_i        : in  std_logic;
    stop_condition_i         : in  std_logic;
-- rx, tx comms
    waiting_for_data_i       : in std_logic;
    rx_done_i                : in std_logic;
    tx_done_i                : in std_logic;
-- data for address_generator
    address_gen_start_o      : out std_logic;
    address_gen_done_i       : in  std_logic;
    address_gen_store_o      : out std_logic;
-- data for cond generator
    req_start_o              : out std_logic;
    req_stop_o               : out std_logic;
    req_cond_done_i          : in  std_logic;
-- data for scl generator
    req_scl_continuous_o     : out std_logic;
-- active component
    cond_gen_o               : out std_logic;
    address_gen_o            : out std_logic;
    receive_o                : out std_logic;
    transmit_o               : out std_logic;
    dev_busy_o               : out std_logic;
    bus_busy_o               : out std_logic);

end entity master_state;

architecture a1 of master_state is
  type state_t is (
    IDLE,
    GENERATING_START,                   -- requesting start condition
    GENERATED_START,                    -- start condition generated, waiting
                                        -- for gen done
    GENERATING_ADDRESS,
    TRANSMITTING,
    RECEIVING,
    GENERATING_STOP,
    GENERATED_STOP,
    BUS_BUSY,
    ERR);

  signal curr_state : state_t;
  signal next_state : state_t;

  signal curr_err_arbitration : std_logic;
  signal next_err_arbitration : std_logic;

  signal curr_err_noack_data : std_logic;
  signal next_err_noack_data : std_logic;

  signal curr_err_noack_address : std_logic;
  signal next_err_noack_address : std_logic;

  signal curr_err_general : std_logic;
  signal next_err_general : std_logic;

  signal curr_gen_start_req : std_logic;
  signal next_gen_start_req : std_logic;

  signal curr_gen_stop_req : std_logic;
  signal next_gen_stop_req : std_logic;

  signal any_err, any_terminal_err : std_logic;
  signal control_over_bus : std_logic;
  signal can_gen_cond : std_logic;
  signal cond_gen : std_logic;
begin  -- architecture a1
  any_err <= curr_err_arbitration or curr_err_noack_data or curr_err_noack_address or curr_err_general;
  any_terminal_err <= curr_err_noack_data or curr_err_noack_address or curr_err_general;
  control_over_bus <= '1' when curr_state /= IDLE and curr_state /= BUS_BUSY else '0';
  can_gen_cond <= '1' when (curr_state = IDLE and start_condition_i = '0' and stop_condition_i = '0') or
                           ((curr_state = TRANSMITTING or curr_state = RECEIVING) and (waiting_for_data_i = '1' or tx_done_i = '1' or rx_done_i = '1')) else '0';

  req_scl_continuous_o <= '1' when curr_state = GENERATING_ADDRESS or
                          curr_state = TRANSMITTING or curr_state = RECEIVING else '0';

  req_start_o <= '1' when curr_state = GENERATING_START or curr_state = GENERATED_START else '0';
  req_stop_o <= '1' when curr_state = GENERATING_STOP or curr_state = GENERATED_STOP else '0';
  cond_gen_o <= cond_gen;
  dev_busy_o <= '1' when curr_state /= IDLE and curr_state /= BUS_BUSY and curr_state /= ERR else '0';

  address_gen_start_o <= '1' when curr_state = GENERATED_START and next_state = GENERATING_ADDRESS else '0';
  address_gen_store_o <= start_i;

  receive_o <= '1' when curr_state = RECEIVING else '0';
  transmit_o <= '1' when curr_state = TRANSMITTING else '0';
  address_gen_o <= '1' when curr_state = GENERATING_ADDRESS else '0';
  bus_busy_o <= '1' when curr_state = BUS_BUSY else '0';

  err_noack_address_o <= curr_err_noack_address;
  err_noack_data_o <= curr_err_noack_data;
  err_arbitration_o <= curr_err_arbitration;
  err_general_o <= curr_err_general;

  cond_gen <= '1' when
                curr_state = GENERATING_STOP or curr_state = GENERATED_STOP or
                curr_state = GENERATING_START or curr_state = GENERATED_START else '0';

  rst_i2c_o <= any_err or cond_gen;

  next_gen_start_req <= '0' when curr_state = GENERATING_START or curr_state = GENERATED_START else
                        '1' when start_i = '1' and run_i = '1' else
                        curr_gen_start_req;

  next_gen_stop_req <= '0' when curr_state = GENERATING_STOP or curr_state = GENERATED_STOP else
                       '1' when stop_i = '1' else
                        curr_gen_stop_req;

  next_err_general <= '0' when curr_state = GENERATING_START else
                      '1' when curr_err_general = '1' else
                      '1' when curr_state = GENERATING_STOP and start_condition_i = '1' else
                      '1' when curr_state = GENERATING_START and stop_condition_i = '1' else
                      '1' when curr_state /= GENERATING_STOP and control_over_bus = '1' and stop_condition_i = '1' else
                      '1' when curr_state /= GENERATING_START and control_over_bus = '1' and start_condition_i = '1' else
                      '1' when curr_state = ERR else
                      '0';

  next_err_arbitration <= '0' when start_condition_i = '1' else
                          '1' when curr_err_arbitration = '1' else
                          '1' when unexpected_sda_data_i = '1' and curr_state = TRANSMITTING else
                          '1' when unexpected_sda_address_i = '1' and curr_state = GENERATING_ADDRESS else
                          '1' when condition_early_i = '1' and curr_state = GENERATED_START else
                          '0';

  next_err_noack_data <= '0' when start_condition_i = '1' else
                         '1' when curr_err_noack_data = '1' else
                         '1' when noack_data_i = '1' and curr_state = TRANSMITTING and expect_ack_i = '1' else
                         '0';

  next_err_noack_address <= '0' when start_condition_i = '1' else
                            '1' when curr_err_noack_address = '1' else
                            '1' when noack_address_i = '1' and curr_state = GENERATING_ADDRESS and expect_ack_i = '1' else
                            '0';

  set_next_state: process (all) is
  begin  -- process set_next_state
    next_state <= curr_state;

    if curr_state = IDLE then
      if start_condition_i = '1' then
        next_state <= BUS_BUSY;
      end if;
    elsif curr_state = GENERATING_START then
      if start_condition_i = '1' then
        next_state <= GENERATED_START;
      elsif req_cond_done_i = '1' then
        -- done before cond generated?
        -- That's not right...
        next_state <= ERR;
      end if;
    elsif curr_state = GENERATED_START then
      if any_terminal_err = '1' then
        next_state <= GENERATING_STOP;
      elsif req_cond_done_i = '1' then
        next_state <= GENERATING_ADDRESS;
      elsif condition_early_i = '1' then
        next_state <= BUS_BUSY;
      end if;
    elsif curr_state = GENERATING_ADDRESS then
      if any_terminal_err = '1' then
        next_state <= GENERATING_STOP;
      elsif address_gen_done_i = '1' then
        if any_err = '1' then
          next_state <= GENERATING_STOP;
        elsif rw_i = '0' then
          next_state <= TRANSMITTING;
        else
          next_state <= RECEIVING;
        end if;
      end if;
    elsif curr_state = TRANSMITTING then
      if any_terminal_err = '1' then
        next_state <= GENERATING_STOP;
      end if;
    elsif curr_state = RECEIVING then
      if any_terminal_err = '1' then
        next_state <= GENERATING_STOP;
      end if;
    elsif curr_state = GENERATING_STOP then
      if stop_condition_i = '1' then
        next_state <= GENERATED_STOP;
      elsif req_cond_done_i = '1' then
        -- done before cond generated?
        -- That's not right...
        next_state <= ERR;
      end if;
    elsif curr_state = GENERATED_STOP then
      if req_cond_done_i = '1' then
        next_state <= IDLE;
      elsif condition_early_i = '1' then
        next_state <= IDLE;
      end if;
    elsif curr_state = ERR then
      -- not much to do
      -- This state should not be possible
      -- if the components in i2c master are
      -- behaving correctly
    elsif curr_state = BUS_BUSY then
      if stop_condition_i = '1' then
        next_state <= IDLE;
      end if;
    end if;

    if can_gen_cond = '1' then
      if curr_gen_start_req = '1' and curr_state /= GENERATING_START and curr_state /= GENERATED_START then
        next_state <= GENERATING_START;
       
        -- if no control over bus, do not
        -- allow generating stop condition
        -- TODO consider not checking that?
      elsif curr_gen_stop_req = '1' and control_over_bus = '1' and curr_state /= GENERATING_STOP and curr_state /= GENERATED_STOP then
        next_state <= GENERATING_STOP;
      end if;
    end if;

    if curr_err_arbitration = '1' and (curr_state = GENERATING_ADDRESS or curr_state = TRANSMITTING) then
      next_state <= BUS_BUSY;
    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_err_arbitration <= '0';
        curr_err_noack_data <= '0';
        curr_err_noack_address <= '0';
        curr_err_general <= '0';
        curr_gen_start_req <= '0';
        curr_gen_stop_req <= '0';
      else
        curr_state <= next_state;
        curr_err_arbitration <= next_err_arbitration;
        curr_err_noack_data <= next_err_noack_data;
        curr_err_noack_address <= next_err_noack_address;
        curr_err_general <= next_err_general;
        curr_gen_start_req <= next_gen_start_req;
        curr_gen_stop_req <= next_gen_stop_req;
      end if;
    end if;
  end process set_regs;

end architecture a1;
Do not follow this link