~ruther/vhdl-i2c

ref: 57bc4031f549c4c98b9f726cf3ca7681299aa521 vhdl-i2c/src/i2c/startstop_condition_generator.vhd -rw-r--r-- 5.9 KiB
57bc4031 — Rutherther feat: store address, rw in address generator or detector 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
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
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library utils;

entity startstop_condition_generator is

  generic (
    DELAY : integer range 0 to 31);

  port (
    clk_i                 : in  std_logic;
    rst_in                : in  std_logic;

    sda_i                 : in  std_logic;
    scl_rising_i          : in  std_logic;
    scl_falling_i         : in  std_logic;
    scl_falling_delayed_i : in  std_logic;
    sda_enable_o          : out std_logic;

    start_condition_i     : in  std_logic;
    stop_condition_i      : in  std_logic;

    gen_start_i           : in  std_logic;
    gen_stop_i            : in  std_logic;

    req_scl_fall_o        : out std_logic;
    req_scl_rise_o        : out std_logic;

    early_condition_o     : out std_logic;

    done_o                : out std_logic);

end entity startstop_condition_generator;

architecture a1 of startstop_condition_generator is
  -- 1. prepare sda to NOT condition level,
  -- 2. request to rise the scl line,
  -- 3. generate the condition - set sda to condition level,
  -- 4. request to fall the scl line (this is to allow for disengaging sda_enable
  -- and take it from another entity instead, without communicating the current
  -- level.),
  -- 5. done!
  type state_t is (IDLE, PREREQ_SCL_FALL, PREPARE_SDA, REQ_SCL_RISE, GEN_COND, REQ_SCL_FALL, EARLY_COND, DONE);
  signal curr_state : state_t := IDLE;
  signal next_state : state_t;

  signal curr_count : integer range 0 to DELAY;
  signal next_count : integer range 0 to DELAY;

  signal curr_scl : std_logic;
  signal next_scl : std_logic;

  signal curr_count_en : std_logic;
  signal next_count_en : std_logic;

  signal request_sda : std_logic;
  signal any_request : std_logic;
begin  -- architecture a1
  any_request <= gen_start_i or gen_stop_i;
  request_sda <= '0' when gen_start_i = '1' else
                 '1' when gen_stop_i = '1' else
                 'X';

  done_o <= '1' when curr_state = DONE else '0';
  early_condition_o <=  '1' when curr_state = EARLY_COND else '0';

  req_scl_rise_o <= '1' when curr_state = REQ_SCL_RISE else '0';
  req_scl_fall_o <= '1' when curr_state = REQ_SCL_FALL or curr_state = PREREQ_SCL_FALL else '0';

  sda_enable_o <= request_sda when curr_state = PREPARE_SDA or curr_state = REQ_SCL_RISE else
                  not request_sda when curr_state = GEN_COND or curr_state = REQ_SCL_FALL else
                  '0';

  next_scl <= '1' when scl_rising_i = '1' else
              '0' when scl_falling_delayed_i = '1' else
              curr_scl;

  next_count <= 0 when curr_state /= next_state else
                curr_count + 1 when curr_count < DELAY and curr_count_en = '1' else
                curr_count;

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

    if curr_state = IDLE then
      next_count_en <= '0';

      if any_request = '1' then
        if curr_scl = '1' and sda_i /= not request_sda then
          next_state <= PREREQ_SCL_FALL;
        elsif curr_scl = '1' then
          next_state <= GEN_COND;
        elsif sda_i = not request_sda then
          next_state <= REQ_SCL_RISE;
        else
          next_state <= PREPARE_SDA;
        end if;
      end if;
    elsif curr_state = PREREQ_SCL_FALL then
      if scl_falling_i = '1' then
        next_count_en <= '1';
      elsif curr_count = DELAY then
        next_state <= PREPARE_SDA;
        next_count_en <= '0';
      elsif curr_scl = '1' then
        next_count_en <= '0';
      end if;
    elsif curr_state = PREPARE_SDA then
      next_count_en <= '1';

      if curr_scl = '1' then
        -- cannot do anything :(
      elsif curr_count = DELAY then
        next_state <= REQ_SCL_RISE;
        next_count_en <= '0';
      elsif curr_scl = '1' then
        next_state <= GEN_COND;
        next_count_en <= '0';
      end if;
    elsif curr_state = REQ_SCL_RISE then
      if scl_rising_i = '1' then
        next_count_en <= '1';
      elsif curr_count = DELAY then
        next_state <= GEN_COND;
        next_count_en <= '0';
      elsif curr_scl = '1' then
        next_count_en <= '1';
      end if;
    elsif curr_state = GEN_COND then
      -- assume correct condition here. If it's the wrong one,
      -- state entity should take care of that. (abort)
      if start_condition_i = '1' or stop_condition_i = '1' then
        next_count_en <= '1';
      elsif curr_count = DELAY then
        if gen_start_i = '1' then
          next_state <= REQ_SCL_FALL;
        else
          next_state <= DONE;
        end if;
        next_count_en <= '0';
      end if;
    elsif curr_state = REQ_SCL_FALL then
      if scl_falling_i = '1' then
        next_count_en <= '1';
      elsif curr_count = DELAY then
        next_state <= DONE;
        next_count_en <= '0';
      elsif curr_scl = '0' then
        next_count_en <= '1';
      end if;
    elsif curr_state = DONE then
      next_count_en <= '0';
      if any_request = '0' then
        next_state <= IDLE;
      end if;
    elsif curr_state = EARLY_COND then
      next_count_en <= '0';
      if any_request = '0' then
        next_state <= IDLE;
      end if;
    end if;

    if start_condition_i = '1' or stop_condition_i = '1' then
      if curr_state = PREREQ_SCL_FALL or curr_state = PREPARE_SDA or curr_state = REQ_SCL_RISE then
        next_state <= EARLY_COND;
      end if;
    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_count <= 0;
        curr_count_en <= '0';
        curr_scl <= '1';
      else
        curr_scl <= next_scl;
        curr_state <= next_state;
        curr_count <= next_count;
        curr_count_en <= next_count_en;
      end if;
    end if;
  end process set_regs;

end architecture a1;
Do not follow this link