Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

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