OpenCores
URL https://opencores.org/ocsvn/i2c/i2c/trunk

Subversion Repositories i2c

[/] [i2c/] [trunk/] [rtl/] [verilog/] [i2c_master_bit_ctrl.v] - Blame information for rev 30

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 rherveille
/////////////////////////////////////////////////////////////////////
2
////                                                             ////
3
////  WISHBONE rev.B2 compliant I2C Master 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) 2001 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 10 rherveille
//
40 30 rherveille
//  $Id: i2c_master_bit_ctrl.v,v 1.7 2002-12-26 16:05:12 rherveille Exp $
41 10 rherveille
//
42 30 rherveille
//  $Date: 2002-12-26 16:05:12 $
43
//  $Revision: 1.7 $
44 14 rherveille
//  $Author: rherveille $
45
//  $Locker:  $
46
//  $State: Exp $
47 10 rherveille
//
48 14 rherveille
// Change History:
49
//               $Log: not supported by cvs2svn $
50 30 rherveille
//               Revision 1.6  2002/12/26 15:02:32  rherveille
51
//               Core is now a Multimaster I2C controller
52
//
53 29 rherveille
//               Revision 1.5  2002/11/30 22:24:40  rherveille
54
//               Cleaned up code
55
//
56 27 rherveille
//               Revision 1.4  2002/10/30 18:10:07  rherveille
57
//               Fixed some reported minor start/stop generation timing issuess.
58
//
59 24 rherveille
//               Revision 1.3  2002/06/15 07:37:03  rherveille
60
//               Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
61
//
62 22 rherveille
//               Revision 1.2  2001/11/05 11:59:25  rherveille
63
//               Fixed wb_ack_o generation bug.
64
//               Fixed bug in the byte_controller statemachine.
65
//               Added headers.
66
//
67 10 rherveille
 
68
//
69
/////////////////////////////////////
70
// Bit controller section
71
/////////////////////////////////////
72
//
73
// Translate simple commands into SCL/SDA transitions
74
// Each command has 5 states, A/B/C/D/idle
75
//
76
// start:       SCL     ~~~~~~~~~~\____
77
//      SDA     ~~~~~~~~\______
78
//               x | A | B | C | D | i
79
//
80
// repstart     SCL     ____/~~~~\___
81
//      SDA     __/~~~\______
82
//               x | A | B | C | D | i
83
//
84
// stop SCL     ____/~~~~~~~~
85
//      SDA     ==\____/~~~~~
86
//               x | A | B | C | D | i
87
//
88
//- write       SCL     ____/~~~~\____
89
//      SDA     ==X=========X=
90
//               x | A | B | C | D | i
91
//
92
//- read        SCL     ____/~~~~\____
93
//      SDA     XXXX=====XXXX
94
//               x | A | B | C | D | i
95
//
96
 
97 24 rherveille
// Timing:     Normal mode      Fast mode
98 10 rherveille
///////////////////////////////////////////////////////////////////////
99 24 rherveille
// Fscl        100KHz           400KHz
100
// Th_scl      4.0us            0.6us   High period of SCL
101
// Tl_scl      4.7us            1.3us   Low period of SCL
102
// Tsu:sta     4.7us            0.6us   setup time for a repeated start condition
103
// Tsu:sto     4.0us            0.6us   setup time for a stop conditon
104
// Tbuf        4.7us            1.3us   Bus free time between a stop and start condition
105 10 rherveille
//
106
 
107 29 rherveille
// synopsys translate_off
108 10 rherveille
`include "timescale.v"
109 29 rherveille
// synopsys translate_on
110
 
111 10 rherveille
`include "i2c_master_defines.v"
112
 
113 29 rherveille
module i2c_master_bit_ctrl(
114
        clk, rst, nReset,
115
        clk_cnt, ena, cmd, cmd_ack, busy, al, din, dout,
116
        scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen
117
        );
118 10 rherveille
 
119
        //
120
        // inputs & outputs
121
        //
122
        input clk;
123
        input rst;
124
        input nReset;
125
        input ena;            // core enable signal
126
 
127
        input [15:0] clk_cnt; // clock prescale value
128
 
129
        input  [3:0] cmd;
130 29 rherveille
        output       cmd_ack; // command complete acknowledge
131 10 rherveille
        reg cmd_ack;
132 29 rherveille
        output       busy;    // i2c bus busy
133 10 rherveille
        reg busy;
134 29 rherveille
        output       al;      // i2c bus arbitration lost
135
        reg al;
136 10 rherveille
 
137
        input  din;
138
        output dout;
139
        reg dout;
140
 
141
        // I2C lines
142 29 rherveille
        input  scl_i;         // i2c clock line input
143
        output scl_o;         // i2c clock line output
144
        output scl_oen;       // i2c clock line output enable (active low)
145 10 rherveille
        reg scl_oen;
146 29 rherveille
        input  sda_i;         // i2c data line input
147
        output sda_o;         // i2c data line output
148
        output sda_oen;       // i2c data line output enable (active low)
149 10 rherveille
        reg sda_oen;
150
 
151
 
152
        //
153
        // variable declarations
154
        //
155
 
156 22 rherveille
        reg sSCL, sSDA;             // synchronized SCL and SDA inputs
157
        reg dscl_oen;               // delayed scl_oen
158 29 rherveille
        reg sda_chk;                // check SDA output (Multi-master arbitration)
159 10 rherveille
        reg clk_en;                 // clock generation signals
160
        wire slave_wait;
161 22 rherveille
//      reg [15:0] cnt = clk_cnt;   // clock divider counter (simulation)
162 10 rherveille
        reg [15:0] cnt;             // clock divider counter (synthesis)
163
 
164
        //
165
        // module body
166
        //
167
 
168 29 rherveille
        // whenever the slave is not ready it can delay the cycle by pulling SCL low
169 22 rherveille
        // delay scl_oen
170
        always @(posedge clk)
171 24 rherveille
          dscl_oen <= #1 scl_oen;
172 22 rherveille
 
173
        assign slave_wait = dscl_oen && !sSCL;
174 10 rherveille
 
175 29 rherveille
 
176 10 rherveille
        // generate clk enable signal
177 24 rherveille
        always @(posedge clk or negedge nReset)
178
          if(~nReset)
179
            begin
180
                cnt    <= #1 16'h0;
181
                clk_en <= #1 1'b1;
182
            end
183
          else if (rst)
184
            begin
185
                cnt    <= #1 16'h0;
186
                clk_en <= #1 1'b1;
187
            end
188 29 rherveille
          else if ( ~|cnt || ~ena)
189
            if (~slave_wait)
190
              begin
191
                  cnt    <= #1 clk_cnt;
192
                  clk_en <= #1 1'b1;
193
              end
194
            else
195
              begin
196
                  cnt    <= #1 cnt;
197
                  clk_en <= #1 1'b0;
198
              end
199 24 rherveille
          else
200
            begin
201 29 rherveille
                cnt    <= #1 cnt - 16'h1;
202 24 rherveille
                clk_en <= #1 1'b0;
203
            end
204 10 rherveille
 
205
 
206
        // generate bus status controller
207 29 rherveille
        reg dSCL, dSDA;
208 10 rherveille
        reg sta_condition;
209
        reg sto_condition;
210
 
211 29 rherveille
        // synchronize SCL and SDA inputs
212
        // reduce metastability risc
213
        always @(posedge clk)
214
          begin
215
              sSCL <= #1 scl_i;
216
              sSDA <= #1 sda_i;
217
 
218
              dSCL <= #1 sSCL;
219
              dSDA <= #1 sSDA;
220
          end
221
 
222 10 rherveille
        // detect start condition => detect falling edge on SDA while SCL is high
223
        // detect stop condition => detect rising edge on SDA while SCL is high
224 24 rherveille
        always @(posedge clk)
225
          begin
226 27 rherveille
              sta_condition <= #1 ~sSDA &  dSDA & sSCL;
227
              sto_condition <= #1  sSDA & ~dSDA & sSCL;
228 24 rherveille
          end
229 10 rherveille
 
230 30 rherveille
        // generate i2c bus busy signal
231 24 rherveille
        always @(posedge clk or negedge nReset)
232
          if(!nReset)
233
            busy <= #1 1'b0;
234
          else if (rst)
235
            busy <= #1 1'b0;
236
          else
237 27 rherveille
            busy <= #1 (sta_condition | busy) & ~sto_condition;
238 10 rherveille
 
239 29 rherveille
        // generate arbitration lost signal
240
        // aribitration lost when:
241
        // 1) master drives SDA high, but the i2c bus is low
242
        // 2) stop detected while not requested
243
        reg cmd_stop, dcmd_stop;
244
        always @(posedge clk)
245
        begin
246
          cmd_stop  <= #1 cmd == `I2C_CMD_STOP;
247
          dcmd_stop <= #1 cmd_stop;
248 10 rherveille
 
249 29 rherveille
          al <= #1 (sda_chk & ~sSDA & sda_oen) | (sto_condition & ~dcmd_stop);
250
        end
251
 
252
        // generate dout signal (store SDA on rising edge of SCL)
253
        always @(posedge clk)
254
          if(sSCL & ~dSCL)
255
            dout <= #1 sSDA;
256
 
257 10 rherveille
        // generate statemachine
258
 
259
        // nxt_state decoder
260 24 rherveille
        parameter [16:0] idle    = 17'b0_0000_0000_0000_0000;
261
        parameter [16:0] start_a = 17'b0_0000_0000_0000_0001;
262
        parameter [16:0] start_b = 17'b0_0000_0000_0000_0010;
263
        parameter [16:0] start_c = 17'b0_0000_0000_0000_0100;
264
        parameter [16:0] start_d = 17'b0_0000_0000_0000_1000;
265
        parameter [16:0] start_e = 17'b0_0000_0000_0001_0000;
266
        parameter [16:0] stop_a  = 17'b0_0000_0000_0010_0000;
267
        parameter [16:0] stop_b  = 17'b0_0000_0000_0100_0000;
268
        parameter [16:0] stop_c  = 17'b0_0000_0000_1000_0000;
269
        parameter [16:0] stop_d  = 17'b0_0000_0001_0000_0000;
270
        parameter [16:0] rd_a    = 17'b0_0000_0010_0000_0000;
271
        parameter [16:0] rd_b    = 17'b0_0000_0100_0000_0000;
272
        parameter [16:0] rd_c    = 17'b0_0000_1000_0000_0000;
273
        parameter [16:0] rd_d    = 17'b0_0001_0000_0000_0000;
274
        parameter [16:0] wr_a    = 17'b0_0010_0000_0000_0000;
275
        parameter [16:0] wr_b    = 17'b0_0100_0000_0000_0000;
276
        parameter [16:0] wr_c    = 17'b0_1000_0000_0000_0000;
277
        parameter [16:0] wr_d    = 17'b1_0000_0000_0000_0000;
278 10 rherveille
 
279 27 rherveille
        reg [16:0] c_state; // synopsis enum_state
280 10 rherveille
 
281 24 rherveille
        always @(posedge clk or negedge nReset)
282
          if (!nReset)
283
            begin
284
                c_state <= #1 idle;
285
                cmd_ack <= #1 1'b0;
286 27 rherveille
                scl_oen <= #1 1'b1;
287
                sda_oen <= #1 1'b1;
288 29 rherveille
                sda_chk <= #1 1'b0;
289 24 rherveille
            end
290 29 rherveille
          else if (rst | al)
291 24 rherveille
            begin
292
                c_state <= #1 idle;
293
                cmd_ack <= #1 1'b0;
294 27 rherveille
                scl_oen <= #1 1'b1;
295
                sda_oen <= #1 1'b1;
296 29 rherveille
                sda_chk <= #1 1'b0;
297 24 rherveille
            end
298
          else
299
            begin
300 27 rherveille
                cmd_ack   <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle
301
 
302 24 rherveille
                if (clk_en)
303 27 rherveille
                  case (c_state) // synopsis full_case parallel_case
304
                    // idle state
305
                    idle:
306
                    begin
307
                        case (cmd) // synopsis full_case parallel_case
308
                          `I2C_CMD_START:
309
                             c_state <= #1 start_a;
310 10 rherveille
 
311 27 rherveille
                          `I2C_CMD_STOP:
312
                             c_state <= #1 stop_a;
313 10 rherveille
 
314 27 rherveille
                          `I2C_CMD_WRITE:
315
                             c_state <= #1 wr_a;
316 10 rherveille
 
317 27 rherveille
                          `I2C_CMD_READ:
318
                             c_state <= #1 rd_a;
319 10 rherveille
 
320 27 rherveille
                          default:
321
                            c_state <= #1 idle;
322
                        endcase
323 10 rherveille
 
324 27 rherveille
                        scl_oen <= #1 scl_oen; // keep SCL in same state
325
                        sda_oen <= #1 sda_oen; // keep SDA in same state
326 29 rherveille
                        sda_chk <= #1 1'b0;    // don't check SDA output
327 27 rherveille
                    end
328 10 rherveille
 
329 27 rherveille
                    // start
330
                    start_a:
331
                    begin
332
                        c_state <= #1 start_b;
333
                        scl_oen <= #1 scl_oen; // keep SCL in same state
334
                        sda_oen <= #1 1'b1;    // set SDA high
335 29 rherveille
                        sda_chk <= #1 1'b0;    // don't check SDA output
336 27 rherveille
                    end
337 10 rherveille
 
338 27 rherveille
                    start_b:
339
                    begin
340
                        c_state <= #1 start_c;
341
                        scl_oen <= #1 1'b1; // set SCL high
342
                        sda_oen <= #1 1'b1; // keep SDA high
343 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
344 27 rherveille
                    end
345 10 rherveille
 
346 27 rherveille
                    start_c:
347
                    begin
348
                        c_state <= #1 start_d;
349
                        scl_oen <= #1 1'b1; // keep SCL high
350
                        sda_oen <= #1 1'b0; // set SDA low
351 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
352 27 rherveille
                    end
353 10 rherveille
 
354 27 rherveille
                    start_d:
355
                    begin
356
                        c_state <= #1 start_e;
357
                        scl_oen <= #1 1'b1; // keep SCL high
358
                        sda_oen <= #1 1'b0; // keep SDA low
359 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
360 27 rherveille
                    end
361 10 rherveille
 
362 27 rherveille
                    start_e:
363
                    begin
364
                        c_state <= #1 idle;
365
                        cmd_ack <= #1 1'b1;
366
                        scl_oen <= #1 1'b0; // set SCL low
367
                        sda_oen <= #1 1'b0; // keep SDA low
368 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
369 27 rherveille
                    end
370 10 rherveille
 
371 27 rherveille
                    // stop
372
                    stop_a:
373
                    begin
374
                        c_state <= #1 stop_b;
375
                        scl_oen <= #1 1'b0; // keep SCL low
376
                        sda_oen <= #1 1'b0; // set SDA low
377 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
378 27 rherveille
                    end
379 10 rherveille
 
380 27 rherveille
                    stop_b:
381
                    begin
382
                        c_state <= #1 stop_c;
383
                        scl_oen <= #1 1'b1; // set SCL high
384
                        sda_oen <= #1 1'b0; // keep SDA low
385 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
386 27 rherveille
                    end
387 10 rherveille
 
388 27 rherveille
                    stop_c:
389
                    begin
390
                        c_state <= #1 stop_d;
391
                        scl_oen <= #1 1'b1; // keep SCL high
392
                        sda_oen <= #1 1'b0; // keep SDA low
393 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
394 27 rherveille
                    end
395 10 rherveille
 
396 27 rherveille
                    stop_d:
397
                    begin
398
                        c_state <= #1 idle;
399
                        cmd_ack <= #1 clk_en;
400
                        scl_oen <= #1 1'b1; // keep SCL high
401
                        sda_oen <= #1 1'b1; // set SDA high
402 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
403 27 rherveille
                    end
404 10 rherveille
 
405 27 rherveille
                    // read
406
                    rd_a:
407
                    begin
408
                        c_state <= #1 rd_b;
409
                        scl_oen <= #1 1'b0; // keep SCL low
410
                        sda_oen <= #1 1'b1; // tri-state SDA
411 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
412 27 rherveille
                    end
413 10 rherveille
 
414 27 rherveille
                    rd_b:
415
                    begin
416
                        c_state <= #1 rd_c;
417
                        scl_oen <= #1 1'b1; // set SCL high
418
                        sda_oen <= #1 1'b1; // keep SDA tri-stated
419 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output
420 27 rherveille
                    end
421 10 rherveille
 
422 27 rherveille
                    rd_c:
423
                    begin
424
                        c_state <= #1 rd_d;
425
                        scl_oen <= #1 1'b1; // keep SCL high
426 29 rherveille
                        sda_oen <= #1 1'b1; // keep SDA tri-stated
427
                        sda_chk <= #1 1'b0; // don't check SDA output
428 27 rherveille
                    end
429 10 rherveille
 
430 27 rherveille
                    rd_d:
431
                    begin
432
                        c_state <= #1 idle;
433
                        cmd_ack <= #1 clk_en;
434
                        scl_oen <= #1 1'b0; // set SCL low
435 29 rherveille
                        sda_oen <= #1 1'b1; // keep SDA tri-stated
436
                        sda_chk <= #1 1'b0; // don't check SDA output
437 27 rherveille
                    end
438 10 rherveille
 
439 27 rherveille
                    // write
440
                    wr_a:
441
                    begin
442
                        c_state <= #1 wr_b;
443
                        scl_oen <= #1 1'b0; // keep SCL low
444
                        sda_oen <= #1 din;  // set SDA
445 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
446 27 rherveille
                    end
447 10 rherveille
 
448 27 rherveille
                    wr_b:
449
                    begin
450
                        c_state <= #1 wr_c;
451
                        scl_oen <= #1 1'b1; // set SCL high
452
                        sda_oen <= #1 din;  // keep SDA
453 29 rherveille
                        sda_chk <= #1 1'b1; // check SDA output
454 27 rherveille
                    end
455 10 rherveille
 
456 27 rherveille
                    wr_c:
457
                    begin
458
                        c_state <= #1 wr_d;
459
                        scl_oen <= #1 1'b1; // keep SCL high
460
                        sda_oen <= #1 din;
461 29 rherveille
                        sda_chk <= #1 1'b1; // check SDA output
462 27 rherveille
                    end
463 24 rherveille
 
464 27 rherveille
                    wr_d:
465
                    begin
466
                        c_state <= #1 idle;
467
                        cmd_ack <= #1 1'b1;
468
                        scl_oen <= #1 1'b0; // set SCL low
469
                        sda_oen <= #1 din;
470 29 rherveille
                        sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
471 27 rherveille
                    end
472 24 rherveille
 
473 27 rherveille
                  endcase
474
            end
475 24 rherveille
 
476 27 rherveille
 
477
        // assign scl and sda output (always gnd)
478
        assign scl_o = 1'b0;
479
        assign sda_o = 1'b0;
480
 
481 10 rherveille
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.