Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

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