Subversion Repositories Code-Repo

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
228 Kevin 1
#include "defines.h"
2
#include "base_I2C.h"
3
 
4
static I2C_DATA *i2c_data_p;
5
 
6
// Set up the data structures for the base_I2C.code
7
// Should be called once before any i2c routines are called
8
void I2C_Init(I2C_DATA *data) {
9
    i2c_data_p = data;
10
 
11
    i2c_data_p->buffer_in_len = 0;
12
    i2c_data_p->buffer_in_len_tmp = 0;
13
    i2c_data_p->buffer_in_read_ind = 0;
14
    i2c_data_p->buffer_in_write_ind = 0;
15
 
16
    i2c_data_p->buffer_out_ind = 0;
17
    i2c_data_p->buffer_out_len = 0;
18
 
19
    i2c_data_p->operating_mode = 0;
20
    i2c_data_p->operating_state = I2C_IDLE;
21
    i2c_data_p->return_status = 0;
22
 
23
    i2c_data_p->slave_in_last_byte = 0;
24
    i2c_data_p->slave_sending_data = 0;
25
 
26
    i2c_data_p->master_dest_addr = 0;
27
    i2c_data_p->master_status = I2C_MASTER_IDLE;
28
 
29
    // Enable I2C interrupt
30
    PIE1bits.SSP1IE = 1;
31
}
32
 
33
// Setup the PIC to operate as a master.
232 Kevin 34
void I2C_Configure_Master(uint8_t speed) {
228 Kevin 35
    i2c_data_p->operating_mode = I2C_MODE_MASTER;
36
 
37
    I2C_CLK_TRIS = 1;
38
    I2C_DAT_TRIS = 1;
39
 
40
    SSPSTAT = 0x0;
41
    SSPCON1 = 0x0;
42
    SSPCON2 = 0x0;
43
    SSPCON1bits.SSPM = 0x8; // I2C Master Mode
44
    if (!speed) {
45
        SSPADD = 0x13;          // Operate at 400KHz (32MHz)
46
    } else {
47
        SSPADD = 0x4F;          // Operate at 100KHz (32MHz)
48
    }
49
    SSPSTATbits.SMP = 1;    // Disable Slew Rate Control
50
    SSPCON1bits.SSPEN = 1;  // Enable MSSP Module
51
}
52
 
53
// Sends length number of bytes in msg to specified address (no R/W bit)
232 Kevin 54
void I2C_Master_Send(uint8_t address, uint8_t length, uint8_t *msg) {
55
    uint8_t i;
228 Kevin 56
    if (length == 0)
57
        return;
58
 
59
    // Copy message to send into buffer and save length/address
60
    for (i = 0; i < length; i++) {
61
        i2c_data_p->buffer_in[i] = msg[i];
62
    }
63
    i2c_data_p->buffer_in_len = length;
64
    i2c_data_p->master_dest_addr = address;
65
    i2c_data_p->buffer_in_read_ind = 0;
66
    i2c_data_p->buffer_in_write_ind = 0;
67
 
68
    // Change status to 'next' operation
69
    i2c_data_p->operating_state = I2C_SEND_ADDR;
70
    i2c_data_p->master_status = I2C_MASTER_SEND;
71
 
72
    // Generate start condition
73
    SSPCON2bits.SEN = 1;
74
}
75
 
76
// Reads length number of bytes from address (no R/W bit)
232 Kevin 77
void I2C_Master_Recv(uint8_t address, uint8_t length) {
228 Kevin 78
    if (length == 0)
79
        return;
80
 
81
    // Save length and address to get data from
82
    i2c_data_p->buffer_in_len = length;
83
    i2c_data_p->master_dest_addr = address;
84
    i2c_data_p->buffer_in_read_ind = 0;
85
    i2c_data_p->buffer_in_write_ind = 0;
86
 
87
    // Change status to 'next' operation
88
    i2c_data_p->operating_state = I2C_SEND_ADDR;
89
    i2c_data_p->master_status = I2C_MASTER_RECV;
90
 
91
    // Generate start condition
92
    SSPCON2bits.SEN = 1;
93
}
94
 
95
// Writes msg to address then reads length number of bytes from address
232 Kevin 96
void I2C_Master_Restart(uint8_t address, uint8_t msg, uint8_t length) {
97
    uint8_t c;
228 Kevin 98
    if (length == 0) {
99
        c = msg;
100
        I2C_Master_Send(address, 1, &c);
101
        return;
102
    }
103
 
104
    // Save length and address to get data from
105
    i2c_data_p->buffer_in[0] = msg;
106
    i2c_data_p->buffer_in_len = length;
107
    i2c_data_p->master_dest_addr = address;
108
    i2c_data_p->buffer_in_read_ind = 0;
109
    i2c_data_p->buffer_in_write_ind = 0;
110
 
111
    // Change status to 'next' operation
112
    i2c_data_p->operating_state = I2C_SEND_ADDR;
113
    i2c_data_p->master_status = I2C_MASTER_RESTART;
114
 
115
    // Generate start condition
116
    SSPCON2bits.SEN = 1;
117
}
118
 
119
// Setup the PIC to operate as a slave. The address must not include the R/W bit
232 Kevin 120
void I2C_Configure_Slave(uint8_t addr) {
228 Kevin 121
    i2c_data_p->operating_mode = I2C_MODE_SLAVE;
122
 
123
    // Ensure the two lines are set for input (we are a slave)
124
    I2C_CLK_TRIS = 1;
125
    I2C_DAT_TRIS = 1;
126
 
127
    SSPADD = addr << 1;     // Set the slave address
128
 
129
    SSPSTAT = 0x0;
130
    SSPCON1 = 0x0;
131
    SSPCON2 = 0x0;
132
    SSPCON1bits.SSPM = 0xE; // Enable Slave 7-bit w/ start/stop interrupts
133
    SSPSTATbits.SMP = 1;    // Slew Off
134
    SSPCON2bits.SEN = 1;    // Enable clock-stretching
135
    SSPCON1bits.SSPEN = 1;  // Enable MSSP Module
136
}
137
 
138
void I2C_Interrupt_Handler() {
139
    // Call interrupt depending on which mode we are operating in
140
    if (i2c_data_p->operating_mode == I2C_MODE_MASTER) {
141
        I2C_Interrupt_Master();
142
    } else if (i2c_data_p->operating_mode == I2C_MODE_SLAVE) {
143
        I2C_Interrupt_Slave();
144
    }
145
}
146
 
147
// An internal subroutine used in the master version of the i2c_interrupt_handler
148
void I2C_Interrupt_Master() {
149
    // If we are in the middle of sending data
150
    if (i2c_data_p->master_status == I2C_MASTER_SEND) {
151
        switch (i2c_data_p->operating_state) {
152
            case I2C_IDLE:
153
                break;
154
            case I2C_SEND_ADDR:
155
                // Send the address with read bit set
156
                i2c_data_p->operating_state = I2C_CHECK_ACK_SEND;
157
                SSPBUF = (i2c_data_p->master_dest_addr << 1) | 0x0;
158
                break;
159
            case I2C_CHECK_ACK_SEND:
160
                // Check if ACK is received or not
161
                if (!SSPCON2bits.ACKSTAT) {
162
                    // If an ACK is received, send next byte of data
163
                    if (i2c_data_p->buffer_in_read_ind < i2c_data_p->buffer_in_len) {
164
                        SSPBUF = i2c_data_p->buffer_in[i2c_data_p->buffer_in_read_ind];
165
                        i2c_data_p->buffer_in_read_ind++;
166
                    } else {
167
                        // If no more data is to be sent, send stop bit
168
                        i2c_data_p->operating_state = I2C_IDLE;
169
                        SSPCON2bits.PEN = 1;
170
                        i2c_data_p->master_status = I2C_MASTER_IDLE;
171
                        i2c_data_p->return_status = I2C_SEND_OK;
172
                    }
173
                } else {
174
                    // If a NACK is received, stop transmission and send error
175
                    i2c_data_p->operating_state = I2C_IDLE;
176
                    SSPCON2bits.PEN = 1;
177
                    i2c_data_p->master_status = I2C_MASTER_IDLE;
178
                    i2c_data_p->return_status = I2C_SEND_FAIL;
179
                }
180
                break;
181
        }
182
    // If we are in the middle of receiving data
183
    } else if (i2c_data_p->master_status == I2C_MASTER_RECV) {
184
        switch (i2c_data_p->operating_state) {
185
            case I2C_IDLE:
186
                break;
187
            case I2C_SEND_ADDR:
188
                // Send address with write bit set
189
                i2c_data_p->operating_state = I2C_CHECK_ACK_RECV;
190
                SSPBUF = (i2c_data_p->master_dest_addr << 1) | 0x1;
191
                break;
192
            case I2C_CHECK_ACK_RECV:
193
                // Check if ACK is received
194
                if (!SSPCON2bits.ACKSTAT) {
195
                    // If an ACK is received, set module to receive 1 byte of data
196
                    i2c_data_p->operating_state = I2C_RCV_DATA;
197
                    SSPCON2bits.RCEN = 1;
198
                } else {
199
                    // If a NACK is received, stop transmission and send error
200
                    i2c_data_p->operating_state = I2C_IDLE;
201
                    SSPCON2bits.PEN = 1;
202
                    i2c_data_p->master_status = I2C_MASTER_IDLE;
203
                    i2c_data_p->return_status = I2C_RECV_FAIL;
204
                }
205
                break;
206
            case I2C_RCV_DATA:
207
                // On receive, save byte into buffer
208
                // TODO: Handle I2C buffer overflow
209
                i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = SSPBUF;
210
                i2c_data_p->buffer_in_write_ind++;
211
                if (i2c_data_p->buffer_in_write_ind < i2c_data_p->buffer_in_len) {
212
                    // If we still need to read, send an ACK to the slave
213
                    i2c_data_p->operating_state = I2C_REQ_DATA;
214
                    SSPCON2bits.ACKDT = 0;  // ACK
215
                    SSPCON2bits.ACKEN = 1;
216
                } else {
217
                    // If we are done reading, send an NACK to the slave
218
                    i2c_data_p->operating_state = I2C_SEND_STOP;
219
                    SSPCON2bits.ACKDT = 1;  // NACK
220
                    SSPCON2bits.ACKEN = 1;
221
                }
222
                break;
223
            case I2C_REQ_DATA:
224
                // Set module to receive one byte of data
225
                i2c_data_p->operating_state = I2C_RCV_DATA;
226
                SSPCON2bits.RCEN = 1;
227
                break;
228
            case I2C_SEND_STOP:
229
                // Send the stop bit and copy message to send to Main()
230
                i2c_data_p->operating_state = I2C_IDLE;
231
                SSPCON2bits.PEN = 1;
232
                i2c_data_p->master_status = I2C_MASTER_IDLE;
233
                i2c_data_p->return_status = I2C_RECV_OK;
234
                break;
235
        }
236
    } else if (i2c_data_p->master_status == I2C_MASTER_RESTART) {
237
        switch (i2c_data_p->operating_state) {
238
            case I2C_IDLE:
239
                break;
240
            case I2C_SEND_ADDR:
241
                // Send the address with read bit set
242
                i2c_data_p->operating_state = I2C_CHECK_ACK_SEND;
243
                SSPBUF = (i2c_data_p->master_dest_addr << 1) | 0x0;
244
                break;
245
            case I2C_CHECK_ACK_SEND:
246
                // Check if ACK is received or not
247
                if (!SSPCON2bits.ACKSTAT) {
248
                    // If an ACK is received, send first byte of data
249
                    SSPBUF = i2c_data_p->buffer_in[0];
250
                    i2c_data_p->operating_state = I2C_CHECK_ACK_RESTART;
251
                } else {
252
                    // If a NACK is received, stop transmission and send error
253
                    i2c_data_p->operating_state = I2C_IDLE;
254
                    SSPCON2bits.PEN = 1;
255
                    i2c_data_p->master_status = I2C_MASTER_IDLE;
256
                    i2c_data_p->return_status = I2C_SEND_FAIL;
257
                }
258
                break;
259
            case I2C_CHECK_ACK_RESTART:
260
                if (!SSPCON2bits.ACKSTAT) {
261
                    SSPCON2bits.RSEN = 1;
262
                    i2c_data_p->operating_state = I2C_SEND_ADDR_2;
263
                } else {
264
                    // If a NACK is received, stop transmission and send error
265
                    i2c_data_p->operating_state = I2C_IDLE;
266
                    SSPCON2bits.PEN = 1;
267
                    i2c_data_p->master_status = I2C_MASTER_IDLE;
268
                    i2c_data_p->return_status = I2C_SEND_FAIL;
269
                }
270
                break;
271
            case I2C_SEND_ADDR_2:
272
                // Send the address with read bit set
273
                i2c_data_p->operating_state = I2C_CHECK_ACK_RECV;
274
                SSPBUF = (i2c_data_p->master_dest_addr << 1) | 0x1;
275
                break;
276
            case I2C_CHECK_ACK_RECV:
277
                // Check if ACK is received
278
                if (!SSPCON2bits.ACKSTAT) {
279
                    // If an ACK is received, set module to receive 1 byte of data
280
                    i2c_data_p->operating_state = I2C_RCV_DATA;
281
                    SSPCON2bits.RCEN = 1;
282
                } else {
283
                    // If a NACK is received, stop transmission and send error
284
                    i2c_data_p->operating_state = I2C_IDLE;
285
                    SSPCON2bits.PEN = 1;
286
                    i2c_data_p->master_status = I2C_MASTER_IDLE;
287
                    i2c_data_p->return_status = I2C_RECV_FAIL;
288
                }
289
                break;
290
            case I2C_RCV_DATA:
291
                // On receive, save byte into buffer
292
                // TODO: Handle I2C buffer overflow
293
                i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = SSPBUF;
294
                i2c_data_p->buffer_in_write_ind++;
295
                if (i2c_data_p->buffer_in_write_ind < i2c_data_p->buffer_in_len) {
296
                    // If we still need to read, send an ACK to the slave
297
                    i2c_data_p->operating_state = I2C_REQ_DATA;
298
                    SSPCON2bits.ACKDT = 0;  // ACK
299
                    SSPCON2bits.ACKEN = 1;
300
                } else {
301
                    // If we are done reading, send an NACK to the slave
302
                    i2c_data_p->operating_state = I2C_SEND_STOP;
303
                    SSPCON2bits.ACKDT = 1;  // NACK
304
                    SSPCON2bits.ACKEN = 1;
305
                }
306
                break;
307
            case I2C_REQ_DATA:
308
                // Set module to receive one byte of data
309
                i2c_data_p->operating_state = I2C_RCV_DATA;
310
                SSPCON2bits.RCEN = 1;
311
                break;
312
            case I2C_SEND_STOP:
236 Kevin 313
                // Send the stop bit
228 Kevin 314
                i2c_data_p->operating_state = I2C_IDLE;
315
                SSPCON2bits.PEN = 1;
316
                i2c_data_p->master_status = I2C_MASTER_IDLE;
317
                i2c_data_p->return_status = I2C_RECV_OK;
318
                break;
319
        }
320
    }
321
}
322
 
323
void I2C_Interrupt_Slave() {
232 Kevin 324
    uint8_t received_data;
325
    uint8_t data_read_from_buffer = 0;
326
    uint8_t data_written_to_buffer = 0;
327
    uint8_t overrun_error = 0;
228 Kevin 328
 
329
    // Clear SSPOV (overflow bit)
330
    if (SSPCON1bits.SSPOV == 1) {
331
        SSPCON1bits.SSPOV = 0;
332
        // We failed to read the buffer in time, so we know we
333
        //  can't properly receive this message, just put us in the
334
        //  a state where we are looking for a new message
335
        i2c_data_p->operating_state = I2C_IDLE;
336
        overrun_error = 1;
337
        i2c_data_p->return_status = I2C_ERR_OVERRUN;
338
    }
339
 
340
    // Read SPPxBUF if it is full
341
    if (SSPSTATbits.BF == 1) {
342
        received_data = SSPBUF;
343
//        DBG_PRINT_I2C("I2C: data read from buffer: %x\r\n", SSPBUF);
344
        data_read_from_buffer = 1;
345
    }
346
 
347
    if (!overrun_error) {
348
        switch (i2c_data_p->operating_state) {
349
            case I2C_IDLE:
350
            {
351
                // Ignore anything except a start
352
                if (SSPSTATbits.S == 1) {
353
                    i2c_data_p->buffer_in_len_tmp = 0;
354
                    i2c_data_p->operating_state = I2C_STARTED;
355
                }
356
                break;
357
            }
358
            case I2C_STARTED:
359
            {
360
                // In this case, we expect either an address or a stop bit
361
                if (SSPSTATbits.P == 1) {
362
                    // Return to idle mode
363
                    i2c_data_p->operating_state = I2C_IDLE;
364
                } else if (data_read_from_buffer) {
365
                    if (SSPSTATbits.D_nA == 0) {
366
                        // Address received
367
                        if (SSPSTATbits.R_nW == 0) {
368
                            // Slave write mode
369
                            i2c_data_p->operating_state = I2C_RCV_DATA;
370
                        } else {
371
                            // Slave read mode
372
                            i2c_data_p->operating_state = I2C_SEND_DATA;
373
                            // Process the first byte immediatly if sending data
374
                            goto send;
375
                        }
376
                    } else {
377
                        i2c_data_p->operating_state = I2C_IDLE;
378
                        i2c_data_p->return_status = I2C_ERR_NODATA;
379
                    }
380
                }
381
                break;
382
            }
383
            send:
384
            case I2C_SEND_DATA:
385
            {
386
                if (!i2c_data_p->slave_sending_data) {
387
                    // If we are not currently sending data, figure out what to reply with
232 Kevin 388
                    if (I2C_Process_Receive(i2c_data_p->slave_in_last_byte)) {
228 Kevin 389
                        // Data exists to be returned, send first byte
390
                        SSPBUF = i2c_data_p->buffer_out[0];
391
                        i2c_data_p->buffer_out_ind = 1;
392
                        i2c_data_p->slave_sending_data = 1;
393
                        data_written_to_buffer = 1;
394
                    } else {
395
                        // Unknown request
396
                        i2c_data_p->slave_sending_data = 0;
397
                        i2c_data_p->operating_state = I2C_IDLE;
398
                    }
399
                } else {
400
                    // Sending remaining data back to master
401
                    if (i2c_data_p->buffer_out_ind < i2c_data_p->buffer_out_len) {
402
                        SSPBUF = i2c_data_p->buffer_out[i2c_data_p->buffer_out_ind];
403
                        i2c_data_p->buffer_out_ind++;
404
                        data_written_to_buffer = 1;
405
                    } else {
406
                        // Nothing left to send
407
                        i2c_data_p->slave_sending_data = 0;
408
                        i2c_data_p->operating_state = I2C_IDLE;
409
                    }
410
                }
411
                break;
412
            }
413
            case I2C_RCV_DATA:
414
            {
415
                // We expect either data or a stop bit or a (if a restart, an addr)
416
                if (SSPSTATbits.P == 1) {
417
                    // Stop bit detected, we need to check to see if we also read data
418
                    if (data_read_from_buffer) {
419
                        if (SSPSTATbits.D_nA == 1) {
420
                            // Data received with stop bit
421
                            // TODO: Handle I2C buffer overflow
422
                            i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = received_data;
423
                            if (i2c_data_p->buffer_in_write_ind == MAXI2CBUF-1) {
424
                                i2c_data_p->buffer_in_write_ind = 0;
425
                            } else {
426
                                i2c_data_p->buffer_in_write_ind++;
427
                            }
428
                            i2c_data_p->buffer_in_len_tmp++;
429
                            // Save the last byte received
430
                            i2c_data_p->slave_in_last_byte = received_data;
431
                            i2c_data_p->return_status = I2C_DATA_AVAL;
432
                        } else {
433
                            i2c_data_p->operating_state = I2C_IDLE;
434
                            i2c_data_p->return_status = I2C_ERR_NODATA;
435
                        }
436
                    }
437
                    i2c_data_p->buffer_in_len += i2c_data_p->buffer_in_len_tmp;
438
                    i2c_data_p->operating_state = I2C_IDLE;
439
                } else if (data_read_from_buffer) {
440
                    if (SSPSTATbits.D_nA == 1) {
441
                        // Data received
442
                        i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = received_data;
443
                        if (i2c_data_p->buffer_in_write_ind == MAXI2CBUF-1) {
444
                            i2c_data_p->buffer_in_write_ind = 0;
445
                        } else {
446
                            i2c_data_p->buffer_in_write_ind++;
447
                        }
448
                        i2c_data_p->buffer_in_len_tmp++;
449
                        // Save the last byte received
450
                        i2c_data_p->slave_in_last_byte = received_data;
451
                        i2c_data_p->return_status = I2C_DATA_AVAL;
452
                    } else {
453
                        // Restart bit detected
454
                        if (SSPSTATbits.R_nW == 1) {
455
                            i2c_data_p->buffer_in_len += i2c_data_p->buffer_in_len_tmp;
456
                            i2c_data_p->operating_state = I2C_SEND_DATA;
457
                            // Process the first byte immediatly if sending data
458
                            goto send;
459
                        } else {
460
                            // Bad to recv an address again, we aren't ready
461
                            i2c_data_p->operating_state = I2C_IDLE;
462
                            i2c_data_p->return_status = I2C_ERR_NODATA;
463
                        }
464
                    }
465
                }
466
                break;
467
            }
468
        }
469
    }
470
 
471
    // Release the clock stretching bit (if we should)
472
    if (data_read_from_buffer || data_written_to_buffer) {
473
        // Release the clock
474
        if (SSPCON1bits.CKP == 0) {
475
            SSPCON1bits.CKP = 1;
476
        }
477
    }
478
}
479
 
480
/* Returns 0 if I2C module is currently busy, otherwise returns status code */
232 Kevin 481
uint8_t I2C_Get_Status() {
228 Kevin 482
    if (i2c_data_p->operating_mode == I2C_MODE_MASTER) {
483
        if (i2c_data_p->master_status != I2C_MASTER_IDLE || i2c_data_p->buffer_in_len == 0) {
484
            return 0;
485
        } else {
486
            return i2c_data_p->return_status;
487
        }
488
    } else {
489
        if (i2c_data_p->operating_state != I2C_IDLE || i2c_data_p->buffer_in_len == 0) {
490
            return 0;
491
        } else {
492
            return i2c_data_p->return_status;
493
        }
494
    }
495
}
496
 
232 Kevin 497
uint8_t I2C_Buffer_Len() {
228 Kevin 498
    return i2c_data_p->buffer_in_len;
499
}
500
 
501
/* Returns 0 if I2C module is currently busy, otherwise returns buffer length */
232 Kevin 502
uint8_t I2C_Read_Buffer(uint8_t *buffer) {
503
    uint8_t i = 0;
228 Kevin 504
    while (i2c_data_p->buffer_in_len != 0) {
505
        buffer[i] = i2c_data_p->buffer_in[i2c_data_p->buffer_in_read_ind];
506
        i++;
507
        if (i2c_data_p->buffer_in_read_ind == MAXI2CBUF-1) {
508
            i2c_data_p->buffer_in_read_ind = 0;
509
        } else {
510
            i2c_data_p->buffer_in_read_ind++;
511
        }
512
        i2c_data_p->buffer_in_len--;
513
    }
514
    return i;
515
}
516
 
517
/* Put data to be returned here */
232 Kevin 518
uint8_t I2C_Process_Receive(uint8_t c) {
519
    uint8_t ret = 0;
228 Kevin 520
    BTN_STATUS btns;
236 Kevin 521
    CLRWDT();
522
    btns.value = 0;
228 Kevin 523
    switch (c) {
524
        case CMD_QUERY_BTN:
525
            Pins_Read(&btns);
526
            i2c_data_p->buffer_out[0] = btns.value;
527
            i2c_data_p->buffer_out_len = 1;
528
            ret = 1;
529
            break;
530
    }
531
    return ret;
532
}