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 29

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

powered by: WebSVN 2.1.0

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