SURF  1.0
i2c_master_bit_ctrl.vhd
Go to the documentation of this file.
1 ---------------------------------------------------------------------
2 ---- ----
3 ---- WISHBONE revB2 I2C Master Core; bit-controller ----
4 ---- ----
5 ---- ----
6 ---- Author: Richard Herveille ----
7 ---- richard@asics.ws ----
8 ---- www.asics.ws ----
9 ---- ----
10 ---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
11 ---- ----
12 ---------------------------------------------------------------------
13 ---- ----
14 ---- Copyright (C) 2000 Richard Herveille ----
15 ---- richard@asics.ws ----
16 ---- ----
17 ---- This source file may be used and distributed without ----
18 ---- restriction provided that this copyright statement is not ----
19 ---- removed from the file and that any derivative work contains ----
20 ---- the original copyright notice and the associated disclaimer.----
21 ---- ----
22 ---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
23 ---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
24 ---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
25 ---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
26 ---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
27 ---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
28 ---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
29 ---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
30 ---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
31 ---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
32 ---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
33 ---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
34 ---- POSSIBILITY OF SUCH DAMAGE. ----
35 ---- ----
36 ---------------------------------------------------------------------
37 
38 -- CVS Log
39 --
40 -- $Id: i2c_master_bit_ctrl.vhd,v 1.14 2006/10/11 12:10:13 rherveille Exp $
41 --
42 -- $Date: 2006/10/11 12:10:13 $
43 -- $Revision: 1.14 $
44 -- $Author: rherveille $
45 -- $Locker: $
46 -- $State: Exp $
47 --
48 -- Change History:
49 -- $Log: i2c_master_bit_ctrl.vhd,v $
50 -- Revision 1.14 2006/10/11 12:10:13 rherveille
51 -- Added missing semicolons ';' on endif
52 --
53 -- Revision 1.13 2006/10/06 10:48:24 rherveille
54 -- fixed short scl high pulse after clock stretch
55 --
56 -- Revision 1.12 2004/05/07 11:53:31 rherveille
57 -- Fixed previous fix :) Made a variable vs signal mistake.
58 --
59 -- Revision 1.11 2004/05/07 11:04:00 rherveille
60 -- Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
61 --
62 -- Revision 1.10 2004/02/27 07:49:43 rherveille
63 -- Fixed a bug in the arbitration-lost signal generation. VHDL version only.
64 --
65 -- Revision 1.9 2003/08/12 14:48:37 rherveille
66 -- Forgot an 'end if' :-/
67 --
68 -- Revision 1.8 2003/08/09 07:01:13 rherveille
69 -- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
70 -- Fixed a potential bug in the byte controller's host-acknowledge generation.
71 --
72 -- Revision 1.7 2003/02/05 00:06:02 rherveille
73 -- Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
74 --
75 -- Revision 1.6 2003/02/01 02:03:06 rherveille
76 -- Fixed a few 'arbitration lost' bugs. VHDL version only.
77 --
78 -- Revision 1.5 2002/12/26 16:05:47 rherveille
79 -- Core is now a Multimaster I2C controller.
80 --
81 -- Revision 1.4 2002/11/30 22:24:37 rherveille
82 -- Cleaned up code
83 --
84 -- Revision 1.3 2002/10/30 18:09:53 rherveille
85 -- Fixed some reported minor start/stop generation timing issuess.
86 --
87 -- Revision 1.2 2002/06/15 07:37:04 rherveille
88 -- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
89 --
90 -- Revision 1.1 2001/11/05 12:02:33 rherveille
91 --! @see entity
92  --! @ingroup protocols_i2c
93 -- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version.
94 -- Code updated, is now up-to-date to doc. rev.0.4.
95 -- Added headers.
96 --
97 -- Modified by Jan Andersson (jan@gaisler.com):
98 --
99 -- * Added two start states to fulfill Set-up time for
100 -- repeated START condition.
101 -- * Modified synchronization of SCL and SDA. START and STOP detection
102 -- is now performed after a two stage synchronizer and is also
103 -- filtered.
104 -- * Changed evaluation order of 'slave_wait', 'en' and 'cnt' in
105 -- generation of clk_en signal to prevent clk_en assertion when
106 -- slave_wait is asserted.
107 -- * Needed to differentiate between slave clock stretching and master
108 -- clock synchronization.
109 -- * Added register s_state which contains the next state in case
110 -- of clock synchronization
111 -- * Incorporated change in wr_b state from SVN rev. 72 of
112 -- original OC version (delay check of SDA).
113 -- * Added 'filter' generic that determines length of filter.
114 -- Original OC core has a median filter implemented. The solution
115 -- implemented in this version is a plain shift register with a
116 -- length determined by the new generic. All samples in this
117 -- register must be equal, otherwise the SCL or SDA value used by
118 -- the core will not be changed. Every SCL/SDA transition that is
119 -- not stable for 'filter' system clock cycles is disregarded.
120 -- This solution is potentially more vulnerable against short
121 -- periods of relatively quick fluctuations on the line, however
122 -- it should do a better job of ignoring 50 ns pulses and still
123 -- allow us to respond quickly to events on the line - assuming
124 -- that the core has been correctly configured.
125 -- Core revision has been increased to 2 (in GRLIB PnP)
126 -- * Added 'dynfilt' generic to allow dynamic adjustment of the
127 -- filter. This component takes in a filt vector that is used to
128 -- reload a filter counter. The filt vector is assigned via the
129 -- core's APB interface.
130 -- Reorganized parts of the code, moving signals into blocks.
131 -- Core revision increased to 3.
132 --
133 -------------------------------------
134 -- Bit controller section
135 ------------------------------------
136 --
137 -- Translate simple commands into SCL/SDA transitions
138 -- Each command has 5 states, A/B/C/D/idle
139 --
140 -- start: SCL ~~~~~~~~~~~~~~\____
141 -- SDA XX/~~~~~~~\______
142 -- x | A | B | C | D | i
143 --
144 -- repstart SCL ______/~~~~~~~\___
145 -- SDA __/~~~~~~~\______
146 -- x | A | B | C | D | i
147 --
148 -- stop SCL _______/~~~~~~~~~~~
149 -- SDA ==\___________/~~~~~
150 -- x | A | B | C | D | i
151 --
152 --- write SCL ______/~~~~~~~\____
153 -- SDA XXX===============XX
154 -- x | A | B | C | D | i
155 --
156 --- read SCL ______/~~~~~~~\____
157 -- SDA XXXXXXX=XXXXXXXXXXX
158 -- x | A | B | C | D | i
159 --
160 
161 -- Timing: Normal mode Fast mode
162 -----------------------------------------------------------------
163 -- Fscl 100KHz 400KHz
164 -- Th_scl 4.0us 0.6us High period of SCL
165 -- Tl_scl 4.7us 1.3us Low period of SCL
166 -- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
167 -- Tsu:sto 4.0us 0.6us setup time for a stop conditon
168 -- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
169 --
170 
171 library ieee;
172 use ieee.std_logic_1164.all;
173 --library grlib;
174 use work.stdlib.all;
175 
177  generic (filter : integer; dynfilt : integer);
178  port (
179  clk : in std_logic;
180  rst : in std_logic;
181  nReset : in std_logic;
182  ena : in std_logic; -- core enable signal
183 
184  clk_cnt : in std_logic_vector(15 downto 0); -- clock prescale value
185 
186  cmd : in std_logic_vector(3 downto 0);
187  cmd_ack : out std_logic; -- command completed
188  busy : out std_logic; -- i2c bus busy
189  al : out std_logic; -- arbitration lost
190 
191  din : in std_logic;
192  dout : out std_logic;
193 
194  filt : in std_logic_vector((filter-1)*dynfilt downto 0);
195 
196  -- i2c lines
197  scl_i : in std_logic; -- i2c clock line input
198  scl_o : out std_logic; -- i2c clock line output
199  scl_oen : out std_logic; -- i2c clock line output enable, active low
200  sda_i : in std_logic; -- i2c data line input
201  sda_o : out std_logic; -- i2c data line output
202  sda_oen : out std_logic -- i2c data line output enable, active low
203  );
204 end entity i2c_master_bit_ctrl;
205 
206 architecture structural of i2c_master_bit_ctrl is
207  constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000";
208  constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001";
209  constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010";
210  constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
211  constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
212 
213  type states is (idle, start_a, start_b, start_c, start_d, start_e, start_f, start_g,
214  stop_a, stop_b, stop_c, stop_d, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
215  signal c_state, s_state : states;
216 
217  signal iscl_oen, isda_oen : std_logic; -- internal I2C lines
218  signal sda_chk : std_logic; -- check SDA status (multi-master arbitration)
219  signal fSCL, fSDA : std_logic_vector(1 downto 0); -- Filtered SCL and SDA inputs
220  signal clk_en, slave_wait : std_logic; -- clock generation signals
221  signal ial : std_logic; -- internal arbitration lost signal
222  signal cnt : std_logic_vector(15 downto 0); -- clock divider counter
223  signal csync : std_logic; -- Need to synchronize clock with other master
224 
225 begin
226  -- generate clk enable signal
227  gen_clken: process(clk, nReset)
228  begin
229  if (nReset = '0') then
230  cnt <= (others => '0');
231  clk_en <= '1';
232  elsif (clk'event and clk = '1') then
233  if (rst = '1') then
234  cnt <= (others => '0');
235  clk_en <= '1';
236  elsif (ena = '0' or csync = '1') then
237  cnt <= clk_cnt;
238  clk_en <= '1';
239  elsif (slave_wait = '1') then
240  cnt <= cnt;
241  clk_en <= '0';
242  elsif (cnt = X"0000") then
243  cnt <= clk_cnt;
244  clk_en <= '1';
245  else
246  cnt <= cnt -1;
247  clk_en <= '0';
248  end if;
249  end if;
250  end process gen_clken;
251 
252 
253  -- generate bus status controller
254  bus_status_ctrl: block
255  signal sta_condition : std_logic; -- start detected
256  signal sto_condition : std_logic; -- stop detected
257  signal cmd_stop : std_logic; -- STOP command
258  signal ibusy : std_logic; -- internal busy signal
259  signal slvw_dis : std_logic; -- Slave wait disable;
260  begin
261 
262  -- Static filter
263  staticfilt : if dynfilt = 0 generate
264  sfblock : block
265  constant FR : integer := filter; -- Filter range MSb
266  constant DR : integer := filter + 1; -- Delayed SCL/SDA range MSb
267 
268  signal sSCL, sSDA : std_logic_vector(FR downto 0); -- synchronized SCL and SDA inputs
269  signal discl_oen : std_logic_vector(DR downto 0); -- delayed scl_oen signal
270  signal disda_oen : std_logic_vector(DR downto 0); -- delayed isda_oen
271  begin
272  -- synchronize SCL and SDA inputs
273  synch_scl_sda: process(clk, nReset)
274  begin
275  if (nReset = '0') then
276  sSCL <= (others => '1');
277  sSDA <= (others => '1');
278  fSCL <= (others => '1');
279  fSDA <= (others => '1');
280  elsif (clk'event and clk = '1') then
281  if (rst = '1') then
282  sSCL <= (others => '1');
283  sSDA <= (others => '1');
284  fSCL <= (others => '1');
285  fSDA <= (others => '1');
286  else
287  sSCL <= sSCL(FR-1 downto 0) & scl_i;
288  sSDA <= sSDA(FR-1 downto 0) & sda_i;
289  -- Filtering
290  if andv(sSCL(FR downto 1)) = '1' then
291  fSCL <= fSCL(0) & '1';
292  elsif orv(sSCL(FR downto 1)) = '0' then
293  fSCL <= fSCL(0) & '0';
294  else
295  fSCL <= fSCL;
296  end if;
297  if andv(sSDA(FR downto 1)) = '1' then
298  fSDA <= fSDA(0) & '1';
299  elsif orv(sSDA(FR downto 1)) = '0' then
300  fSDA <= fSDA(0) & '0';
301  else
302  fSDA <= fSDA;
303  end if;
304  end if;
305  end if;
306  end process synch_SCL_SDA;
307 
308  -- whenever the slave is not ready it can delay the cycle by pulling SCL low
309  -- delay scl_oen
310  process (clk)
311  begin
312  if (clk'event and clk = '1') then
313  if rst = '1' then
314  discl_oen <= (others => '1');
315  slvw_dis <= '0';
316  else
317  -- Keep SCL output enable values
318  discl_oen <= discl_oen(DR-1 downto 0) & iscl_oen;
319  -- Disable slave stretch detection when other device drives SCL
320  -- H->L (only a master should to this).
321  slvw_dis <= (slvw_dis or csync) and discl_oen(0);
322  end if;
323  end if;
324  end process;
325  -- SCL forced low after master tried to assert, slave is stretching clock
326  slave_wait <= andv(discl_oen(DR downto 1)) and not fSCL(0) and not (slvw_dis or fSCL(1));
327  -- SCL HIGH time cut short, master clock synchronization
328  csync <= andv(discl_oen(DR downto 1)) and not fSCL(0) and fSCL(1);
329 
330  -- generate arbitration lost signal
331  -- aribitration lost when:
332  -- 1) master drives SDA high, but the i2c bus is low
333  -- 2) stop detected while not requested (detect during 'idle' state)
334  gen_al: process(clk, nReset)
335  begin
336  if (nReset = '0') then
337  cmd_stop <= '0';
338  ial <= '0';
339  disda_oen <= (others => '1');
340  elsif (clk'event and clk = '1') then
341  if (rst = '1') then
342  cmd_stop <= '0';
343  ial <= '0';
344  disda_oen <= (others => '1');
345  else
346  if (clk_en = '1') then
347  if (cmd = I2C_CMD_STOP) then
348  cmd_stop <= '1';
349  else
350  cmd_stop <= '0';
351  end if;
352  end if;
353 
354  if (c_state = idle) then
355  ial <= (sda_chk and not fSDA(0) and disda_oen(DR));
356  else
357  ial <= (sda_chk and not fSDA(0) and disda_oen(DR)) or
358  (sto_condition and not cmd_stop);
359  end if;
360  end if;
361  disda_oen <= disda_oen(DR-1 downto 0) & isda_oen;
362  end if;
363  end process gen_al;
364  end block sfblock;
365  end generate staticfilt;
366 
367  -- Dynamic filter
368  dynamicfilt : if dynfilt /= 0 generate
369  -- Fixed window
370  dfblock : block
371  signal filtcnt : std_logic_vector(filter-1 downto 0);
372  signal sSCL, sSDA : std_logic_vector(1 downto 0); -- synchronized SCL and SDA inputs
373  signal fiscl_oen : std_logic_vector(1 downto 0); -- "filtered" scl_oen signal
374  signal fisda_oen : std_ulogic; -- "filtered" sda_oen signal
375  signal fSCL_chg, fSDA_chg, fiscl_oen_chg, fisda_oen_chg : std_ulogic;
376  signal discl_oen : std_ulogic; -- delayed scl_oen signal
377  signal disda_oen : std_ulogic; -- delayed sda_oen signal
378  begin
379  -- Provides filtered signals for SCL and SDA, and corresponding
380  -- output enable signals.
381  sync_scl_sda: process(clk, nReset, fSCL_chg, fSDA_chg, fiscl_oen_chg, fisda_oen_chg)
382  variable scl_chg, sda_chg, iscl_oen_chg, isda_oen_chg : std_ulogic;
383  begin
384  scl_chg := fSCL_chg; sda_chg := fSDA_chg;
385  iscl_oen_chg := fiscl_oen_chg; isda_oen_chg := fisda_oen_chg;
386  if (nReset = '0') then
387  filtcnt <= (others => '0');
388  fSCL <= (others => '1'); fSDA <= (others => '1');
389  fSCL_chg <= '0'; fSDA_chg <= '0';
390  fiscl_oen <= (others => '1'); fiscl_oen_chg <= '0';
391  fisda_oen <= '1'; fisda_oen_chg <= '0';
392  elsif (clk'event and clk = '1') then
393  if (rst = '1') or (ena = '0') then
394  filtcnt <= (others => '0');
395  fSCL <= (others => '1'); fSDA <= (others => '1');
396  fSCL_chg <= '0'; fSDA_chg <= '0';
397  fiscl_oen <= (others => '1'); fiscl_oen_chg <= '0';
398  fisda_oen <= '1'; fisda_oen_chg <= '0';
399  else
400  if (sSCL(1) xor fSCL(0)) = '0' then scl_chg := '0'; end if;
401  if (sSDA(1) xor fSDA(0)) = '0' then sda_chg := '0'; end if;
402  if (discl_oen xor fiscl_oen(0)) = '0' then iscl_oen_chg := '0'; end if;
403  if (disda_oen xor fisda_oen) = '0' then isda_oen_chg := '0'; end if;
404  if filtcnt = zero32((filter-1)*dynfilt downto 0) then
405  filtcnt <= filt;
406  fSCL <= fSCL(0) & (fSCL(0) xor scl_chg);
407  fSDA <= fSDA(0) & (fSDA(0) xor sda_chg);
408  fSCL_chg <= '1'; fSDA_chg <= '1';
409  fiscl_oen <= fiscl_oen(0) & (fiscl_oen(0) xor iscl_oen_chg);
410  fiscl_oen_chg <= '1';
411  fisda_oen <= fisda_oen xor isda_oen_chg;
412  fisda_oen_chg <= '1';
413  else
414  filtcnt <= filtcnt - 1;
415  fSDA <= fSDA; fSCL <= fSCL;
416  fSCL_chg <= scl_chg; fSDA_chg <= sda_chg;
417  fiscl_oen <= fiscl_oen;
418  fiscl_oen_chg <= iscl_oen_chg;
419  fisda_oen <= fisda_oen;
420  fisda_oen_chg <= isda_oen_chg;
421  end if;
422  end if;
423  sSCL <= sSCL(0) & scl_i;
424  sSDA <= sSDA(0) & sda_i;
425  end if;
426  end process sync_SCL_SDA;
427 
428  -- whenever the slave is not ready it can delay the cycle by pulling SCL low
429  -- delay scl_oen
430  process (clk)
431  begin
432  if (clk'event and clk = '1') then
433  if rst = '1' then
434  discl_oen <= '1';
435  slvw_dis <= '0';
436  else
437  -- Keep SCL output enable values
438  discl_oen <= iscl_oen;
439  -- Disable slave stretch detection when other device drives SCL
440  -- H->L (only a master should to this).
441  slvw_dis <= (slvw_dis or csync) and discl_oen;
442  end if;
443  end if;
444  end process;
445  -- SCL forced low after master tried to assert, slave is stretching clock
446  slave_wait <= andv(fiscl_oen) and not fSCL(0) and not (slvw_dis or fSCL(1));
447  -- SCL HIGH time cut short, master clock synchronization
448  csync <= andv(fiscl_oen) and not fSCL(0) and fSCL(1);
449 
450  -- generate arbitration lost signal
451  -- aribitration lost when:
452  -- 1) master drives SDA high, but the i2c bus is low
453  -- 2) stop detected while not requested (detect during 'idle' state)
454  gen_ald: process(clk, nReset)
455  begin
456  if (nReset = '0') then
457  cmd_stop <= '0';
458  ial <= '0';
459  disda_oen <= '1';
460  elsif (clk'event and clk = '1') then
461  if (rst = '1') then
462  cmd_stop <= '0';
463  ial <= '0';
464  disda_oen <= '1';
465  else
466  if (clk_en = '1') then
467  if (cmd = I2C_CMD_STOP) then
468  cmd_stop <= '1';
469  else
470  cmd_stop <= '0';
471  end if;
472  end if;
473  if (c_state = idle) then
474  ial <= (sda_chk and not fSDA(0) and fisda_oen);
475  else
476  ial <= (sda_chk and not fSDA(0) and fisda_oen) or
477  (sto_condition and not cmd_stop);
478  end if;
479  disda_oen <= isda_oen;
480  end if;
481  end if;
482  end process gen_ald;
483  end block dfblock;
484  end generate dynamicfilt;
485 
486  al <= ial;
487 
488  -- detect start condition => detect falling edge on SDA while SCL is high
489  -- detect stop condition => detect rising edge on SDA while SCL is high
490  detect_sta_sto: process(clk, nReset)
491  begin
492  if (nReset = '0') then
493  sta_condition <= '0';
494  sto_condition <= '0';
495  elsif (clk'event and clk = '1') then
496  if (rst = '1') then
497  sta_condition <= '0';
498  sto_condition <= '0';
499  else
500  if fSCL = "11" and fSDA = "10" then
501  sta_condition <= '1';
502  else
503  sta_condition <= '0';
504  end if;
505  if fSCL = "11" and fSDA = "01" then
506  sto_condition <= '1';
507  else
508  sto_condition <= '0';
509  end if;
510  end if;
511  end if;
512  end process detect_sta_sto;
513 
514  -- generate i2c-bus busy signal
515  gen_busy: process(clk, nReset)
516  begin
517  if (nReset = '0') then
518  ibusy <= '0';
519  elsif (clk'event and clk = '1') then
520  if (rst = '1') then
521  ibusy <= '0';
522  else
523  ibusy <= (sta_condition or ibusy) and not sto_condition;
524  end if;
525  end if;
526  end process gen_busy;
527  busy <= ibusy;
528 
529  -- generate dout signal, store dout on rising edge of SCL
530  gen_dout: process(clk)
531  begin
532  if (clk'event and clk = '1') then
533  if fSCL = "01" then
534  dout <= fSDA(1);
535  end if;
536  end if;
537  end process gen_dout;
538  end block bus_status_ctrl;
539 
540 
541  -- generate statemachine
542  nxt_state_decoder : process (clk, nReset, c_state, cmd)
543  begin
544  if (nReset = '0') then
545  c_state <= idle;
546  s_state <= idle;
547  cmd_ack <= '0';
548  iscl_oen <= '1';
549  isda_oen <= '1';
550  sda_chk <= '0';
551  elsif (clk'event and clk = '1') then
552  if (rst = '1' or ial = '1') then
553  c_state <= idle;
554  cmd_ack <= '0';
555  iscl_oen <= '1';
556  isda_oen <= '1';
557  sda_chk <= '0';
558  elsif csync = '1' then
559  c_state <= s_state;
560  else
561 
562  cmd_ack <= '0'; -- default no acknowledge
563 
564  -- csync is always '0' here, but including it in the expression
565  -- appears to let some compilers optimize the design more...
566  if (clk_en or csync) = '1' then
567 
568  case (c_state) is
569  -- idle
570  when idle =>
571  case cmd is
572  when I2C_CMD_START => c_state <= start_a;
573  s_state <= start_g;
574  when I2C_CMD_STOP => c_state <= stop_a;
575  s_state <= stop_d;
576  when I2C_CMD_WRITE => c_state <= wr_a;
577  s_state <= wr_d;
578  when I2C_CMD_READ => c_state <= rd_a;
579  s_state <= rd_d;
580  when others => c_state <= idle; -- NOP command
581  s_state <= idle;
582  end case;
583 
584  iscl_oen <= iscl_oen; -- keep SCL in same state
585  isda_oen <= isda_oen; -- keep SDA in same state
586  sda_chk <= '0'; -- don't check SDA
587 
588  -- start
589  when start_a =>
590  c_state <= start_b;
591  iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start)
592  isda_oen <= '1'; -- set SDA high
593  sda_chk <= '0'; -- don't check SDA
594 
595  when start_b =>
596  c_state <= start_c;
597  iscl_oen <= '1'; -- set SCL high
598  isda_oen <= '1'; -- keep SDA high
599  sda_chk <= '0'; -- don't check SDA
600 
601  when start_c =>
602  c_state <= start_d;
603  iscl_oen <= '1'; -- set SCL high
604  isda_oen <= '1'; -- keep SDA high
605  sda_chk <= '0'; -- don't check SDA
606 
607  when start_d =>
608  c_state <= start_e;
609  iscl_oen <= '1'; -- set SCL high
610  isda_oen <= '1'; -- keep SDA high
611  sda_chk <= '0'; -- don't check SDA
612 
613  when start_e =>
614  c_state <= start_f;
615  iscl_oen <= '1'; -- keep SCL high
616  isda_oen <= '0'; -- set SDA low
617  sda_chk <= '0'; -- don't check SDA
618 
619  when start_f =>
620  c_state <= start_g;
621  iscl_oen <= '1'; -- keep SCL high
622  isda_oen <= '0'; -- keep SDA low
623  sda_chk <= '0'; -- don't check SDA
624 
625  when start_g =>
626  c_state <= idle;
627  cmd_ack <= '1'; -- command completed
628  iscl_oen <= '0'; -- set SCL low
629  isda_oen <= '0'; -- keep SDA low
630  sda_chk <= '0'; -- don't check SDA
631  s_state <= idle;
632 
633  -- stop
634  when stop_a =>
635  c_state <= stop_b;
636  iscl_oen <= '0'; -- keep SCL low
637  isda_oen <= '0'; -- set SDA low
638  sda_chk <= '0'; -- don't check SDA
639 
640  when stop_b =>
641  c_state <= stop_c;
642  iscl_oen <= '1'; -- set SCL high
643  isda_oen <= '0'; -- keep SDA low
644  sda_chk <= '0'; -- don't check SDA
645 
646  when stop_c =>
647  c_state <= stop_d;
648  iscl_oen <= '1'; -- keep SCL high
649  isda_oen <= '0'; -- keep SDA low
650  sda_chk <= '0'; -- don't check SDA
651 
652  when stop_d =>
653  c_state <= idle;
654  cmd_ack <= '1'; -- command completed
655  iscl_oen <= '1'; -- keep SCL high
656  isda_oen <= '1'; -- set SDA high
657  sda_chk <= '0'; -- don't check SDA
658  s_state <= idle;
659 
660  -- read
661  when rd_a =>
662  c_state <= rd_b;
663  iscl_oen <= '0'; -- keep SCL low
664  isda_oen <= '1'; -- tri-state SDA
665  sda_chk <= '0'; -- don't check SDA
666 
667  when rd_b =>
668  c_state <= rd_c;
669  iscl_oen <= '1'; -- set SCL high
670  isda_oen <= '1'; -- tri-state SDA
671  sda_chk <= '0'; -- don't check SDA
672 
673  when rd_c =>
674  c_state <= rd_d;
675  iscl_oen <= '1'; -- keep SCL high
676  isda_oen <= '1'; -- tri-state SDA
677  sda_chk <= '0'; -- don't check SDA
678 
679  when rd_d =>
680  c_state <= idle;
681  cmd_ack <= '1'; -- command completed
682  iscl_oen <= '0'; -- set SCL low
683  isda_oen <= '1'; -- tri-state SDA
684  sda_chk <= '0'; -- don't check SDA
685  s_state <= idle;
686 
687  -- write
688  when wr_a =>
689  c_state <= wr_b;
690  iscl_oen <= '0'; -- keep SCL low
691  isda_oen <= din; -- set SDA
692  sda_chk <= '0'; -- don't check SDA (SCL low)
693 
694  when wr_b =>
695  c_state <= wr_c;
696  iscl_oen <= '1'; -- set SCL high
697  isda_oen <= din; -- keep SDA
698  sda_chk <= '0'; -- don't check SDA (allow signals to settle)
699 
700  when wr_c =>
701  c_state <= wr_d;
702  iscl_oen <= '1'; -- keep SCL high
703  isda_oen <= din; -- keep SDA
704  sda_chk <= '1'; -- check SDA
705 
706  when wr_d =>
707  c_state <= idle;
708  cmd_ack <= '1'; -- command completed
709  iscl_oen <= '0'; -- set SCL low
710  isda_oen <= din; -- keep SDA
711  sda_chk <= '0'; -- don't check SDA (SCL low)
712  s_state <= idle;
713 
714  when others =>
715 
716  end case;
717  end if;
718  end if;
719  end if;
720  end process nxt_state_decoder;
721 
722 
723  -- assign outputs
724  scl_o <= '0';
725  scl_oen <= iscl_oen;
726  sda_o <= '0';
727  sda_oen <= isda_oen;
728 end architecture structural;
729 
std_logic_vector( 3 downto 0) := "0000" I2C_CMD_NOP
std_logic_vector( DR downto 0) discl_oen
std_logic_vector( filter- 1 downto 0) filtcnt
std_logic_vector( 15 downto 0) cnt
std_logic_vector( 1 downto 0) fiscl_oen
std_logic_vector( 3 downto 0) := "0010" I2C_CMD_STOP
std_logic_vector( 1 downto 0) fSCL
std_logic_vector( DR downto 0) disda_oen
std_logic_vector( FR downto 0) sSDA
std_logic_vector( 3 downto 0) := "1000" I2C_CMD_WRITE
_library_ ieeeieee
(idle,start_a,start_b,start_c,start_d,start_e,start_f,start_g,stop_a,stop_b,stop_c,stop_d,rd_a,rd_b,rd_c,rd_d,wr_a,wr_b,wr_c,wr_d) states
in clk_cntstd_logic_vector( 15 downto 0)
in filtstd_logic_vector(( filter- 1)* dynfilt downto 0)
std_logic_vector( 3 downto 0) := "0001" I2C_CMD_START
std_logic_vector( 1 downto 0) fSDA
std_logic_vector( 3 downto 0) := "0100" I2C_CMD_READ
in cmdstd_logic_vector( 3 downto 0)
std_logic_vector( FR downto 0) sSCL