source: PlatformSupport/CustomPeripherals/pcores/w3_iic_eeprom_v1_00_b/opencores_src/rtl/vhdl/I2C.VHD

Last change on this file was 1766, checked in by murphpo, 12 years ago
File size: 13.2 KB
Line 
1--
2-- Simple I2C controller
3--
4-- 1) No multimaster
5-- 2) No slave mode
6-- 3) No fifo's
7--
8-- notes:
9-- Every command is acknowledged. Do not set a new command before previous is acknowledged.
10-- Dout is available 1 clock cycle later as cmd_ack
11--
12
13library ieee;
14use ieee.std_logic_1164.all;
15use ieee.std_logic_arith.all;
16
17package I2C is
18    component simple_i2c is
19    port (
20        clk : in std_logic;
21        ena : in std_logic;
22        nReset : in std_logic;
23
24        clk_cnt : in unsigned(7 downto 0);  -- 4x SCL
25
26        -- input signals
27        start,
28        stop,
29        read,
30        write,
31        ack_in : std_logic;
32        Din : in std_logic_vector(7 downto 0);
33
34        -- output signals
35        cmd_ack : out std_logic;
36        ack_out : out std_logic;
37        Dout : out std_logic_vector(7 downto 0);
38
39        -- i2c signals
40        SCL : inout std_logic;
41        SDA : inout std_logic
42    );
43    end component simple_i2c;
44end package I2C;
45
46
47library ieee;
48use ieee.std_logic_1164.all;
49use ieee.std_logic_arith.all;
50
51entity simple_i2c is
52    port (
53        clk : in std_logic;
54        ena : in std_logic;
55        nReset : in std_logic;
56
57        clk_cnt : in unsigned(7 downto 0);  -- 4x SCL
58
59        -- input signals
60        start,
61        stop,
62        read,
63        write,
64        ack_in : std_logic;
65        Din : in std_logic_vector(7 downto 0);
66
67        -- output signals
68        cmd_ack : out std_logic;
69        ack_out : out std_logic;
70        Dout : out std_logic_vector(7 downto 0);
71
72        -- i2c signals
73        SCL : inout std_logic;
74        SDA : inout std_logic
75    );
76end entity simple_i2c;
77
78architecture structural of simple_i2c is
79    component i2c_core is
80    port (
81        clk : in std_logic;
82        nReset : in std_logic;
83
84        clk_cnt : in unsigned(7 downto 0);
85
86        cmd : in std_logic_vector(2 downto 0);
87        cmd_ack : out std_logic;
88        busy : out std_logic;
89
90        Din : in std_logic;
91        Dout : out std_logic;
92
93        SCL : inout std_logic;
94        SDA : inout std_logic
95    );
96    end component i2c_core;
97
98    -- commands for i2c_core
99    constant CMD_NOP    : std_logic_vector(2 downto 0) := "000";
100    constant CMD_START  : std_logic_vector(2 downto 0) := "010";
101    constant CMD_STOP   : std_logic_vector(2 downto 0) := "011";
102    constant CMD_READ   : std_logic_vector(2 downto 0) := "100";
103    constant CMD_WRITE  : std_logic_vector(2 downto 0) := "101";
104
105    -- signals for i2c_core
106    signal core_cmd : std_logic_vector(2 downto 0);
107    signal core_ack, core_busy, core_txd, core_rxd : std_logic;
108
109    -- signals for shift register
110    signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
111    signal shift, ld : std_logic;
112
113    -- signals for state machine
114    signal go, host_ack : std_logic;
115begin
116    -- hookup i2c core
117    u1: i2c_core port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_busy, core_txd, core_rxd, SCL, SDA);
118
119    -- generate host-command-acknowledge
120    cmd_ack <= host_ack;
121   
122    -- generate go-signal
123    go <= (read or write) and not host_ack;
124
125    -- assign Dout output to shift-register
126    Dout <= sr;
127
128    -- assign ack_out output to core_rxd (contains last received bit)
129    ack_out <= core_rxd;
130
131    -- generate shift register
132    shift_register: process(clk)
133    begin
134        if (clk'event and clk = '1') then
135            if (ld = '1') then
136                sr <= din;
137            elsif (shift = '1') then
138                sr <= (sr(6 downto 0) & core_rxd);
139            end if;
140        end if;
141    end process shift_register;
142
143    --
144    -- state machine
145    --
146    statemachine : block
147        type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
148        signal state : states;
149        signal dcnt : unsigned(2 downto 0);
150    begin
151        --
152        -- command interpreter, translate complex commands into simpler I2C commands
153        --
154        nxt_state_decoder: process(clk, nReset, state)
155            variable nxt_state : states;
156            variable idcnt : unsigned(2 downto 0);
157            variable ihost_ack : std_logic;
158            variable icore_cmd : std_logic_vector(2 downto 0);
159            variable icore_txd : std_logic;
160            variable ishift, iload : std_logic;
161        begin
162            -- 8 databits (1byte) of data to shift-in/out
163            idcnt := dcnt;
164
165            -- no acknowledge (until command complete)
166            ihost_ack := '0';
167
168            icore_txd := core_txd;
169
170            -- keep current command to i2c_core
171            icore_cmd := core_cmd;
172
173            -- no shifting or loading of shift-register
174            ishift := '0';
175            iload := '0';
176
177            -- keep current state;
178            nxt_state := state;
179            case state is
180                when st_idle =>
181                    if (go = '1') then
182                        if (start = '1') then
183                            nxt_state := st_start; 
184                            icore_cmd := CMD_START;
185                        elsif (read = '1') then
186                            nxt_state := st_read;
187                            icore_cmd := CMD_READ;
188                            idcnt := "111";
189                        else
190                            nxt_state := st_write;
191                            icore_cmd := CMD_WRITE;
192                            idcnt := "111";
193                            iload := '1';
194                        end if;
195                    end if;
196
197                when st_start =>
198                    if (core_ack = '1') then
199                        if (read = '1') then
200                            nxt_state := st_read;
201                            icore_cmd := CMD_READ;
202                            idcnt := "111";
203                        else
204                            nxt_state := st_write;
205                            icore_cmd := CMD_WRITE;
206                            idcnt := "111";
207                            iload := '1';
208                        end if;
209                    end if;
210
211                when st_write =>
212                    if (core_ack = '1') then
213                        idcnt := dcnt -1;   -- count down Data_counter
214                        icore_txd := sr(7);
215                        if (dcnt = 0) then
216                            nxt_state := st_ack;
217                            icore_cmd := CMD_READ;
218                        else
219                            ishift := '1';
220--                          icore_txd := sr(7);
221                        end if;
222                    end if;         
223
224                when st_read =>
225                    if (core_ack = '1') then
226                        idcnt := dcnt -1;   -- count down Data_counter
227                        ishift := '1';
228                        if (dcnt = 0) then
229                            nxt_state := st_ack;
230                            icore_cmd := CMD_WRITE;
231                            icore_txd := ack_in;
232                        end if;
233                    end if;         
234
235                when st_ack =>
236                    if (core_ack = '1') then
237                        -- generate command acknowledge signal
238                        ihost_ack := '1';
239
240                        -- Perform an additional shift, needed for 'read' (store last received bit in shift register)
241                        ishift := '1';
242
243                        -- check for stop; Should a STOP command be generated ?
244                        if (stop = '1') then
245                            nxt_state := st_stop;
246                            icore_cmd := CMD_STOP;
247                        else
248                            nxt_state := st_idle;
249                            icore_cmd := CMD_NOP;
250                        end if;
251                    end if;
252
253                when st_stop =>
254                    if (core_ack = '1') then
255                        nxt_state := st_idle;
256                        icore_cmd := CMD_NOP;
257                    end if;
258
259                when others => -- illegal states
260                    nxt_state := st_idle;
261                    icore_cmd := CMD_NOP;
262            end case;
263
264            -- generate registers
265            if (nReset = '0') then
266                core_cmd <= CMD_NOP;
267                core_txd <= '0';
268               
269                shift <= '0';
270                ld <= '0';
271
272                dcnt <= "111";
273                host_ack <= '0';
274
275                state <= st_idle;
276            elsif (clk'event and clk = '1') then
277                if (ena = '1') then
278                    state <= nxt_state;
279
280                    dcnt <= idcnt;
281                    shift <= ishift;
282                    ld <= iload;
283
284                    core_cmd <= icore_cmd;
285                    core_txd <= icore_txd;
286
287                    host_ack <= ihost_ack;
288                end if;
289            end if;
290        end process nxt_state_decoder;
291
292    end block statemachine;
293
294end architecture structural;
295
296
297--
298--
299-- I2C Core
300--
301-- Translate simple commands into SCL/SDA transitions
302-- Each command has 5 states, A/B/C/D/idle
303--
304-- start:   SCL ~~~~~~~~~~\____
305--  SDA ~~~~~~~~\______
306--       x | A | B | C | D | i
307--
308-- repstart SCL ____/~~~~\___
309--  SDA __/~~~\______
310--       x | A | B | C | D | i
311--
312-- stop SCL ____/~~~~~~~~
313--  SDA ==\____/~~~~~
314--       x | A | B | C | D | i
315--
316--- write   SCL ____/~~~~\____
317--  SDA ==X=========X=
318--       x | A | B | C | D | i
319--
320--- read    SCL ____/~~~~\____
321--  SDA XXXX=====XXXX
322--       x | A | B | C | D | i
323--
324
325-- Timing:      Normal mode Fast mode
326-----------------------------------------------------------------
327-- Fscl     100KHz      400KHz
328-- Th_scl       4.0us       0.6us   High period of SCL
329-- Tl_scl       4.7us       1.3us   Low period of SCL
330-- Tsu:sta      4.7us       0.6us   setup time for a repeated start condition
331-- Tsu:sto      4.0us       0.6us   setup time for a stop conditon
332-- Tbuf     4.7us       1.3us   Bus free time between a stop and start condition
333--
334
335library ieee;
336use ieee.std_logic_1164.all;
337use ieee.std_logic_arith.all;
338
339entity i2c_core is
340    port (
341        clk : in std_logic;
342        nReset : in std_logic;
343
344        clk_cnt : in unsigned(7 downto 0);
345
346        cmd : in std_logic_vector(2 downto 0);
347        cmd_ack : out std_logic;
348        busy : out std_logic;
349
350        Din : in std_logic;
351        Dout : out std_logic;
352
353        SCL : inout std_logic;
354        SDA : inout std_logic
355    );
356end entity i2c_core;
357
358architecture structural of i2c_core is
359    constant CMD_NOP    : std_logic_vector(2 downto 0) := "000";
360    constant CMD_START  : std_logic_vector(2 downto 0) := "010";
361    constant CMD_STOP   : std_logic_vector(2 downto 0) := "011";
362    constant CMD_READ   : std_logic_vector(2 downto 0) := "100";
363    constant CMD_WRITE  : std_logic_vector(2 downto 0) := "101";
364
365    type cmds is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
366    signal state : cmds;
367    signal SDAo, SCLo : std_logic;
368    signal txd : std_logic;
369    signal clk_en, slave_wait :std_logic;
370    signal cnt : unsigned(7 downto 0) := clk_cnt;
371begin
372    -- whenever the slave is not ready it can delay the cycle by pulling SCL low
373    slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0';
374
375    -- generate clk enable signal
376    gen_clken: process(clk, nReset)
377    begin
378        if (nReset = '0') then
379            cnt <= (others => '0');
380            clk_en <= '1'; --'0';
381        elsif (clk'event and clk = '1') then
382            if (cnt = 0) then
383                clk_en <= '1';
384                cnt <= clk_cnt;
385            else
386                if (slave_wait = '0') then
387                    cnt <= cnt -1;
388                end if;
389                clk_en <= '0';
390            end if;
391        end if;
392    end process gen_clken;
393
394    -- generate statemachine
395    nxt_state_decoder : process (clk, nReset, state, cmd, SDA)
396        variable nxt_state : cmds;
397        variable icmd_ack, ibusy, store_sda : std_logic;
398        variable itxd : std_logic;
399    begin
400
401        nxt_state := state;
402
403        icmd_ack := '0'; -- default no acknowledge
404        ibusy := '1'; -- default busy
405
406        store_sda := '0';
407
408        itxd := txd;
409
410        case (state) is
411            -- idle
412            when idle =>
413                case cmd is
414                    when CMD_START =>
415                        nxt_state := start_a;
416                        icmd_ack := '1'; -- command completed
417
418                    when CMD_STOP =>
419                        nxt_state := stop_a;
420                        icmd_ack := '1'; -- command completed
421
422                    when CMD_WRITE =>
423                        nxt_state := wr_a;
424                        icmd_ack := '1'; -- command completed
425                        itxd := Din;
426
427                    when CMD_READ =>
428                        nxt_state := rd_a;
429                        icmd_ack := '1'; -- command completed
430
431                    when others =>
432                        nxt_state := idle;
433-- don't acknowledge NOP command                        icmd_ack := '1'; -- command completed
434                        ibusy := '0';
435                end case;
436
437            -- start
438            when start_a =>
439                nxt_state := start_b;
440
441            when start_b =>
442                nxt_state := start_c;
443
444            when start_c =>
445                nxt_state := start_d;
446
447            when start_d =>
448                nxt_state := idle;
449                ibusy := '0'; -- not busy when idle
450
451
452            -- stop
453            when stop_a =>
454                nxt_state := stop_b;
455
456            when stop_b =>
457                nxt_state := stop_c;
458
459            when stop_c =>
460--              nxt_state := stop_d;
461
462--          when stop_d =>
463                nxt_state := idle;
464                ibusy := '0'; -- not busy when idle
465
466            -- read
467            when rd_a =>
468                nxt_state := rd_b;
469
470            when rd_b =>
471                nxt_state := rd_c;
472
473            when rd_c =>
474                nxt_state := rd_d;
475                store_sda := '1';
476
477            when rd_d =>
478                nxt_state := idle;
479                ibusy := '0'; -- not busy when idle
480
481            -- write
482            when wr_a =>
483                nxt_state := wr_b;
484
485            when wr_b =>
486                nxt_state := wr_c;
487
488            when wr_c =>
489                nxt_state := wr_d;
490
491            when wr_d =>
492                nxt_state := idle;
493                ibusy := '0'; -- not busy when idle
494
495        end case;
496
497        -- generate regs
498        if (nReset = '0') then
499            state <= idle;
500            cmd_ack <= '0';
501            busy <= '0';
502            txd <= '0';
503            Dout <= '0';
504        elsif (clk'event and clk = '1') then
505            if (clk_en = '1') then
506                state <= nxt_state;
507                busy <= ibusy;
508
509                txd <= itxd;
510                if (store_sda = '1') then
511                    Dout <= SDA;
512                end if;
513            end if;
514
515            cmd_ack <= icmd_ack and clk_en;
516        end if;
517    end process nxt_state_decoder;
518
519    --
520    -- convert states to SCL and SDA signals
521    --
522    output_decoder: process (clk, nReset, state)
523        variable iscl, isda : std_logic;
524    begin
525        case (state) is
526            when idle =>
527                iscl := SCLo; -- keep SCL in same state
528                isda := SDA; -- keep SDA in same state
529
530            -- start
531            when start_a =>
532                iscl := SCLo; -- keep SCL in same state (for repeated start)
533                isda := '1'; -- set SDA high
534
535            when start_b =>
536                iscl := '1';    -- set SCL high
537                isda := '1'; -- keep SDA high
538
539            when start_c =>
540                iscl := '1';    -- keep SCL high
541                isda := '0'; -- sel SDA low
542
543            when start_d =>
544                iscl := '0'; -- set SCL low
545                isda := '0'; -- keep SDA low
546
547            -- stop
548            when stop_a =>
549                iscl := '0'; -- keep SCL disabled
550                isda := '0'; -- set SDA low
551
552            when stop_b =>
553                iscl := '1'; -- set SCL high
554                isda := '0'; -- keep SDA low
555
556            when stop_c =>
557                iscl := '1'; -- keep SCL high
558                isda := '1'; -- set SDA high
559
560            -- write
561            when wr_a =>
562                iscl := '0';    -- keep SCL low
563--              isda := txd; -- set SDA
564                isda := Din;
565
566            when wr_b =>
567                iscl := '1';    -- set SCL high
568--              isda := txd; -- set SDA
569                isda := Din;
570
571            when wr_c =>
572                iscl := '1';    -- keep SCL high
573--              isda := txd; -- set SDA
574                isda := Din;
575
576            when wr_d =>
577                iscl := '0'; -- set SCL low
578--              isda := txd; -- set SDA
579                isda := Din;
580
581            -- read
582            when rd_a =>
583                iscl := '0'; -- keep SCL low
584                isda := '1'; -- tri-state SDA
585
586            when rd_b =>
587                iscl := '1'; -- set SCL high
588                isda := '1'; -- tri-state SDA
589
590            when rd_c =>
591                iscl := '1'; -- keep SCL high
592                isda := '1'; -- tri-state SDA
593
594            when rd_d =>
595                iscl := '0'; -- set SCL low
596                isda := '1'; -- tri-state SDA
597        end case;
598
599        -- generate registers
600        if (nReset = '0') then
601            SCLo <= '1';
602            SDAo <= '1';
603        elsif (clk'event and clk = '1') then
604            if (clk_en = '1') then
605                SCLo <= iscl;
606                SDAo <= isda;
607            end if;
608        end if;
609    end process output_decoder;
610
611    SCL <= '0' when (SCLo = '0') else 'Z'; -- since SCL is externally pulled-up convert a '1' to a 'Z'(tri-state)
612    SDA <= '0' when (SDAo = '0') else 'Z'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state)
613--  SCL <= SCLo;
614--  SDA <= SDAo;
615
616end architecture structural;
617
618
619
620
Note: See TracBrowser for help on using the repository browser.