Subversion Repositories Code-Repo

Rev

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

Rev Author Line No. Line
113 Kevin 1
#include "msg_queues.h"
2
#include "maindefs.h"
3
//#include <i2c.h>
4
#include "i2c.h"
5
 
6
#pragma udata i2c_data
7
unsigned char i2c_buffer[MAXI2CBUF];
8
#pragma udata
9
I2C_DATA *i2c_pdata;
10
 
11
// Set up the data structures for the i2c code
12
// Should be called once before any i2c routines are called
13
void i2c_init(I2C_DATA *data) {
14
    i2c_pdata = data;
15
    i2c_pdata->buffer = i2c_buffer;
16
    i2c_pdata->buflen = 0;
17
    i2c_pdata->slave_event_count = 0;
18
    i2c_pdata->status = I2C_IDLE;
19
    i2c_pdata->slave_error_count = 0;
20
    i2c_pdata->bufind = 0;
21
    i2c_pdata->buflen = 0;
22
    i2c_pdata->slave_in_last_byte = 0;
23
    i2c_pdata->slave_sending_data = 0;
24
    i2c_pdata->slave_sending_blank_data = 0;
25
    i2c_pdata->mode = 0;
26
    i2c_pdata->master_dest_addr = 0;
27
    i2c_pdata->master_state = I2C_MASTER_IDLE;
28
}
29
 
30
// Setup the PIC to operate as a master.
31
void i2c_configure_master() {
32
    i2c_pdata->mode = I2C_MODE_MASTER;
33
 
34
    TRISCbits.TRISC3 = 1;
35
    TRISCbits.TRISC4 = 1;
36
 
37
    SSPSTAT = 0x0;
38
    SSPCON1 = 0x0;
39
    SSPCON2 = 0x0;
40
    SSPCON1bits.SSPM = 0x8; // I2C Master Mode
41
    SSPADD = 0x63;          // Operate at 100KHz (40MHz)
42
    SSPSTATbits.SMP = 1;    // Disable Slew Rate Control
43
    SSPCON1bits.SSPEN = 1;  // Enable MSSP Module
44
}
45
 
46
// Sends length number of bytes in msg to specified address (no R/W bit)
47
void i2c_master_send(unsigned char address, unsigned char length, unsigned char *msg) {
48
    int i;
49
    if (length == 0)
50
        return;
51
 
52
    // Copy message to send into buffer and save length/address
53
    for (i = 0; i < length; i++) {
54
        i2c_pdata->buffer[i] = msg[i];
55
    }
56
    i2c_pdata->buflen = length;
57
    i2c_pdata->master_dest_addr = address;
58
    i2c_pdata->bufind = 0;
59
 
60
    // Change status to 'next' operation
61
    i2c_pdata->status = I2C_SEND_ADDR;
62
    i2c_pdata->master_state = I2C_MASTER_SEND;
63
 
64
    // Generate start condition
65
    SSPCON2bits.SEN = 1;
66
}
67
 
68
// Reads length number of bytes from address (no R/W bit)
69
void i2c_master_recv(unsigned char address, unsigned char length) {
70
    if (length == 0)
71
        return;
72
 
73
    // Save length and address to get data from
74
    i2c_pdata->buflen = length;
75
    i2c_pdata->master_dest_addr = address;
76
    i2c_pdata->bufind = 0;
77
 
78
    // Change status to 'next' operation
79
    i2c_pdata->status = I2C_SEND_ADDR;
80
    i2c_pdata->master_state = I2C_MASTER_RECV;
81
 
82
    // Generate start condition
83
    SSPCON2bits.SEN = 1;
84
}
85
 
86
// Setup the PIC to operate as a slave. The address must not include the R/W bit
87
void i2c_configure_slave(unsigned char addr) {
88
    i2c_pdata->mode = I2C_MODE_SLAVE;
89
 
90
    // Ensure the two lines are set for input (we are a slave)
91
    TRISCbits.TRISC3 = 1;
92
    TRISCbits.TRISC4 = 1;
93
 
94
    SSPADD = addr << 1;     // Set the slave address
95
 
96
    SSPSTAT = 0x0;
97
    SSPCON1 = 0x0;
98
    SSPCON2 = 0x0;
99
    SSPCON1bits.SSPM = 0xE; // Enable Slave 7-bit w/ start/stop interrupts
100
    SSPSTATbits.SMP = 1;    // Slew Off
101
    SSPCON2bits.SEN = 1;    // Enable clock-stretching
102
    SSPCON1bits.SSPEN = 1;  // Enable MSSP Module
103
}
104
 
105
void i2c_interrupt_handler() {
106
    // Call interrupt depending on which mode we are operating in
107
    if (i2c_pdata->mode == I2C_MODE_MASTER) {
108
        i2c_interrupt_master();
109
    } else if (i2c_pdata->mode == I2C_MODE_SLAVE) {
110
        i2c_interrupt_slave();
111
    }
112
}
113
 
114
// An internal subroutine used in the master version of the i2c_interrupt_handler
115
void i2c_interrupt_master() {
116
    // If we are in the middle of sending data
117
    if (i2c_pdata->master_state == I2C_MASTER_SEND) {
118
        switch (i2c_pdata->status) {
119
            case I2C_IDLE:
120
                break;
121
            case I2C_SEND_ADDR:
122
                // Send the address with read bit set
123
                i2c_pdata->status = I2C_CHECK_ACK;
124
                SSPBUF = (i2c_pdata->master_dest_addr << 1) | 0x0;
125
                break;
126
            case I2C_CHECK_ACK:
127
                // Check if ACK is received or not
128
                if (!SSPCON2bits.ACKSTAT) {
129
                    // If an ACK is received, send next byte of data
130
                    if (i2c_pdata->bufind < i2c_pdata->buflen) {
131
                        SSPBUF = i2c_pdata->buffer[i2c_pdata->bufind];
132
                        i2c_pdata->bufind++;
133
                    } else {
134
                        // If no more data is to be sent, send stop bit
135
                        i2c_pdata->status = I2C_IDLE;
136
                        SSPCON2bits.PEN = 1;
137
                        i2c_pdata->master_state = I2C_MASTER_IDLE;
138
                        MQ_sendmsg_ToMainFromHigh(0, MSGTYPE_I2C_MASTER_SEND_COMPLETE, (void *) 0);
139
                    }
140
                } else {
141
                    // If a NACK is received, stop transmission and send error
142
                    i2c_pdata->status = I2C_IDLE;
143
                    SSPCON2bits.PEN = 1;
144
                    i2c_pdata->master_state = I2C_MASTER_IDLE;
145
                    MQ_sendmsg_ToMainFromHigh(0, MSGTYPE_I2C_MASTER_SEND_FAILED, (void *) 0);
146
                }
147
                break;
148
        }
149
    // If we are in the middle of receiving data
150
    } else if (i2c_pdata->master_state == I2C_MASTER_RECV) {
151
        switch (i2c_pdata->status) {
152
            case I2C_IDLE:
153
                break;
154
            case I2C_SEND_ADDR:
155
                // Send address with write bit set
156
                i2c_pdata->status = I2C_CHECK_ACK;
157
                SSPBUF = (i2c_pdata->master_dest_addr << 1) | 0x1;
158
                break;
159
            case I2C_CHECK_ACK:
160
                // Check if ACK is received
161
                if (!SSPCON2bits.ACKSTAT) {
162
                    // If an ACK is received, set module to receive 1 byte of data
163
                    i2c_pdata->status = I2C_RCV_DATA;
164
                    SSPCON2bits.RCEN = 1;
165
                } else {
166
                    // If a NACK is received, stop transmission and send error
167
                    i2c_pdata->status = I2C_IDLE;
168
                    SSPCON2bits.PEN = 1;
169
                    i2c_pdata->master_state = I2C_MASTER_IDLE;
170
                    MQ_sendmsg_ToMainFromHigh(0, MSGTYPE_I2C_MASTER_RECV_FAILED, (void *) 0);
171
                }
172
                break;
173
            case I2C_RCV_DATA:
174
                // On receive, save byte into buffer
175
                i2c_pdata->buffer[i2c_pdata->bufind] = SSPBUF;
176
                i2c_pdata->bufind++;
177
                if (i2c_pdata->bufind < i2c_pdata->buflen) {
178
                    // If we still need to read, send an ACK to the slave
179
                    i2c_pdata->status = I2C_REQ_DATA;
180
                    SSPCON2bits.ACKDT = 0;  // ACK
181
                    SSPCON2bits.ACKEN = 1;
182
                } else {
183
                    // If we are done reading, send an NACK to the slave
184
                    i2c_pdata->status = I2C_SEND_STOP;
185
                    SSPCON2bits.ACKDT = 1;  // NACK
186
                    SSPCON2bits.ACKEN = 1;
187
                }
188
                break;
189
            case I2C_REQ_DATA:
190
                // Set module to receive one byte of data
191
                i2c_pdata->status = I2C_RCV_DATA;
192
                SSPCON2bits.RCEN = 1;
193
                break;
194
            case I2C_SEND_STOP:
195
                // Send the stop bit and copy message to send to Main()
196
                i2c_pdata->status = I2C_IDLE;
197
                SSPCON2bits.PEN = 1;
198
                i2c_pdata->master_state = I2C_MASTER_IDLE;
199
                MQ_sendmsg_ToMainFromHigh(i2c_pdata->buflen, MSGTYPE_I2C_MASTER_RECV_COMPLETE, (void *) i2c_pdata->buffer);
200
                break;
201
        }
202
    }
203
}
204
 
205
// An internal subroutine used in the slave version of the i2c_interrupt_handler
206
void i2c_handle_start(unsigned char data_read) {
207
    i2c_pdata->slave_event_count = 1;
208
    i2c_pdata->buflen = 0;
209
 
210
    // Check to see if we also got the address
211
    if (data_read) {
212
        if (SSPSTATbits.D_A == 1) {
213
            DBG_PRINT_I2C("I2C Start: (ERROR) no address recieved\r\n");
214
            // This is bad because we got data and we wanted an address
215
            i2c_pdata->status = I2C_IDLE;
216
            i2c_pdata->slave_error_count++;
217
            i2c_pdata->slave_error_code = I2C_ERR_NOADDR;
218
        } else {
219
            if (SSPSTATbits.R_W == 1) {
220
                i2c_pdata->status = I2C_SEND_DATA;
221
            } else {
222
                i2c_pdata->status = I2C_RCV_DATA;
223
            }
224
        }
225
    } else {
226
        i2c_pdata->status = I2C_STARTED;
227
    }
228
}
229
 
230
void i2c_interrupt_slave() {
231
    unsigned char i2c_data;
232
    unsigned char data_read_from_buffer = 0;
233
    unsigned char data_written_to_buffer = 0;
234
    unsigned char msg_send_data_to_main = 0;
235
    unsigned char overrun_error = 0;
236
    unsigned char error_buf[3];
237
    unsigned char msgtype = 0;
238
 
239
    // Clear SSPOV (overflow bit)
240
    if (SSPCON1bits.SSPOV == 1) {
241
        DBG_PRINT_I2C("I2C: overflow detected\r\n");
242
        SSPCON1bits.SSPOV = 0;
243
        // We failed to read the buffer in time, so we know we
244
        //  can't properly receive this message, just put us in the
245
        //  a state where we are looking for a new message
246
        i2c_pdata->status = I2C_IDLE;
247
        overrun_error = 1;
248
        i2c_pdata->slave_error_count++;
249
        i2c_pdata->slave_error_code = I2C_ERR_OVERRUN;
250
    }
251
 
252
    // Read SPPxBUF if it is full
253
    if (SSPSTATbits.BF == 1) {
254
        i2c_data = SSPBUF;
255
        DBG_PRINT_I2C("I2C: data read from buffer: %x\r\n", SSPBUF);
256
        data_read_from_buffer = 1;
257
    }
258
 
259
    if (!overrun_error) {
260
        switch (i2c_pdata->status) {
261
            case I2C_IDLE:
262
            {
263
                // Ignore anything except a start
264
                if (SSPSTATbits.S == 1) {
265
                    i2c_handle_start(data_read_from_buffer);
266
                    // If we see a slave read, then we need to handle it here
267
                    if (i2c_pdata->status == I2C_SEND_DATA) {
268
                        // Return the first byte (message id)
269
                        SSPBUF = 0x3;
270
                    }
271
                }
272
                break;
273
            }
274
            case I2C_STARTED:
275
            {
276
                // In this case, we expect either an address or a stop bit
277
                if (SSPSTATbits.P == 1) {
278
                    // We need to check to see if we also read an address (a message of length 0)
279
                    i2c_pdata->slave_event_count++;
280
                    if (data_read_from_buffer) {
281
                        if (SSPSTATbits.D_A == 0) {
282
                            msg_send_data_to_main = 1;
283
                        } else {
284
                            DBG_PRINT_I2C("I2C: (ERROR) no data recieved\r\n");
285
                            i2c_pdata->slave_error_count++;
286
                            i2c_pdata->slave_error_code = I2C_ERR_NODATA;
287
                        }
288
                    }
289
                    // Return to idle mode
290
                    i2c_pdata->status = I2C_IDLE;
291
                } else if (data_read_from_buffer) {
292
                    i2c_pdata->slave_event_count++;
293
                    if (SSPSTATbits.D_A == 0) {
294
                        if (SSPSTATbits.R_W == 0) {  // Slave write
295
                            i2c_pdata->status = I2C_RCV_DATA;
296
                        } else {    // Slave read
297
                            i2c_pdata->status = I2C_SEND_DATA;
298
                            // Return the first byte (message id)
299
                            SSPBUF = 0x3;
300
                        }
301
                    } else {
302
                        DBG_PRINT_I2C("I2C: (ERROR) no data recieved\r\n");
303
                        i2c_pdata->slave_error_count++;
304
                        i2c_pdata->status = I2C_IDLE;
305
                        i2c_pdata->slave_error_code = I2C_ERR_NODATA;
306
                    }
307
                }
308
                break;
309
            }
310
            case I2C_SEND_DATA:
311
            {
312
                // If we arnt current in the middle of sending data, check to see
313
                //  if there is a message in the queue to send
314
                if (!i2c_pdata->slave_sending_data) {
315
                    // Check the message type of the next message in queue
316
                    msgtype = MQ_peek_FromMainToHigh();
317
                    if (msgtype != MSGTYPE_I2C_REPLY || msgtype == 0) {
318
                        // If the message queue is empty or to another interrupt processor, return 0xFF
319
                        DBG_PRINT_I2C("I2C: Returning 0xFF [%d:%d]\r\n", 0, i2c_pdata->slave_in_last_byte-1);
320
                        SSPBUF = 0xFF;
321
                        i2c_pdata->bufind = 1;
322
                        i2c_pdata->slave_sending_data = 1;
323
                        i2c_pdata->slave_sending_blank_data = 1;
324
                        data_written_to_buffer = 1;
325
                    } else {
326
                        i2c_pdata->buflen = MQ_recvmsg_FromMainToHigh(MSGLEN, (unsigned char *)i2c_pdata->slave_outbufmsgtype, (void *) i2c_pdata->buffer);
327
//                        DBG_PRINT_I2C("%x\r\n",i2c_ptr->buffer[0]);
328
//                        DBG_PRINT_I2C("I2C: buffer Message Length: %d\r\n",i2c_ptr->outbuflen);
329
                        if (i2c_pdata->buflen > 0) {
330
                            // Otherwise return the first byte of data
331
                            DBG_PRINT_I2C("I2C: Returning %x [%d,%d]\r\n", i2c_pdata->buffer[0], 0, i2c_pdata->buflen-1);
332
                            SSPBUF = i2c_pdata->buffer[0];
333
                            i2c_pdata->bufind = 1;
334
                            i2c_pdata->slave_sending_data = 1;
335
                            data_written_to_buffer = 1;
336
                        } else {
337
                            DBG_PRINT_I2C("I2C: (ERROR) Unexpected msg in queue, type = %x\r\n", i2c_pdata->slave_outbufmsgtype);
338
                        }
339
                    }
340
                } else if (i2c_pdata->slave_sending_blank_data) {
341
                    // If we are currently sending 0xFFs back, keep sending for the requested number of bytes
342
                    if (i2c_pdata->bufind < i2c_pdata->slave_in_last_byte) {
343
                        DBG_PRINT_I2C("I2C: Returning 0xFF [%d:%d]\r\n", i2c_pdata->bufind, i2c_pdata->slave_in_last_byte-1);
344
                        SSPBUF = 0xFF;
345
                        i2c_pdata->bufind++;
346
                        data_written_to_buffer = 1;
347
                    } else {
348
                        // We have nothing left to send
349
                        i2c_pdata->slave_sending_data = 0;
350
                        i2c_pdata->slave_sending_blank_data = 0;
351
                        i2c_pdata->status = I2C_IDLE;
352
                    }
353
                } else {
354
                    // Otherwise keep sending back the requested data
355
                    if (i2c_pdata->bufind < i2c_pdata->buflen) {
356
                        DBG_PRINT_I2C("I2C: Returning %x [%d,%d]\r\n", i2c_pdata->buffer[i2c_pdata->bufind], i2c_pdata->bufind, i2c_pdata->buflen-1);
357
                        SSPBUF = i2c_pdata->buffer[i2c_pdata->bufind];
358
                        i2c_pdata->bufind++;
359
                        data_written_to_buffer = 1;
360
                    } else {
361
                        // We have nothing left to send
362
                        i2c_pdata->slave_sending_data = 0;
363
                        i2c_pdata->status = I2C_IDLE;
364
                    }
365
                }
366
                break;
367
            }
368
            case I2C_RCV_DATA:
369
            {
370
                // We expect either data or a stop bit or a (if a restart, an addr)
371
                if (SSPSTATbits.P == 1) {
372
                    // We need to check to see if we also read data
373
                    i2c_pdata->slave_event_count++;
374
                    if (data_read_from_buffer) {
375
                        if (SSPSTATbits.D_A == 1) {
376
                            i2c_pdata->buffer[i2c_pdata->buflen] = i2c_data;
377
                            i2c_pdata->buflen++;
378
                            msg_send_data_to_main = 1;
379
                        } else {
380
                            DBG_PRINT_I2C("I2C: (ERROR) no data recieved\r\n");
381
                            i2c_pdata->slave_error_count++;
382
                            i2c_pdata->slave_error_code = I2C_ERR_NODATA;
383
                            i2c_pdata->status = I2C_IDLE;
384
                        }
385
                    } else {
386
                        msg_send_data_to_main = 1;
387
                    }
388
                    i2c_pdata->status = I2C_IDLE;
389
                } else if (data_read_from_buffer) {
390
                    i2c_pdata->slave_event_count++;
391
                    if (SSPSTATbits.D_A == 1) {
392
                        i2c_pdata->buffer[i2c_pdata->buflen] = i2c_data;
393
                        i2c_pdata->buflen++;
394
                    } else /* a restart */ {
395
                        if (SSPSTATbits.R_W == 1) {
396
                            i2c_pdata->status = I2C_SEND_DATA;
397
                            msg_send_data_to_main = 1;
398
                            // Return the first byte (message id)
399
                            SSPBUF = 0x3;
400
 
401
                        } else { // Bad to recv an address again, we aren't ready
402
                            DBG_PRINT_I2C("I2C: (ERROR) no data recieved\r\n");
403
                            i2c_pdata->slave_error_count++;
404
                            i2c_pdata->slave_error_code = I2C_ERR_NODATA;
405
                            i2c_pdata->status = I2C_IDLE;
406
                        }
407
                    }
408
                }
409
                break;
410
            }
411
        }
412
    }
413
 
414
    // Release the clock stretching bit (if we should)
415
    if (data_read_from_buffer || data_written_to_buffer) {
416
        // Release the clock
417
        if (SSPCON1bits.CKP == 0) {
418
            SSPCON1bits.CKP = 1;
419
        }
420
    }
421
 
422
    // Must check if the message is too long
423
    if ((i2c_pdata->buflen > MAXI2CBUF - 2) && (!msg_send_data_to_main)) {
424
        DBG_PRINT_I2C("I2C: (ERROR) message too long\r\n");
425
        i2c_pdata->status = I2C_IDLE;
426
        i2c_pdata->slave_error_count++;
427
        i2c_pdata->slave_error_code = I2C_ERR_MSGTOOLONG;
428
    }
429
 
430
    if (msg_send_data_to_main) {
431
        DBG_PRINT_I2C("I2C: sending message to main()\r\n");
432
        i2c_pdata->slave_in_last_byte = i2c_pdata->buffer[i2c_pdata->buflen-1];
433
        i2c_pdata->buffer[i2c_pdata->buflen] = i2c_pdata->slave_event_count;
434
        MQ_sendmsg_ToMainFromHigh(i2c_pdata->buflen + 1, MSGTYPE_I2C_DATA, (void *) i2c_pdata->buffer);
435
        i2c_pdata->buflen = 0;
436
    } else if (i2c_pdata->slave_error_count >= I2C_ERR_THRESHOLD) {
437
        DBG_PRINT_I2C("I2C: (ERROR) error threshold passed\r\n");
438
        error_buf[0] = i2c_pdata->slave_error_count;
439
        error_buf[1] = i2c_pdata->slave_error_code;
440
        error_buf[2] = i2c_pdata->slave_event_count;
441
        MQ_sendmsg_ToMainFromHigh(sizeof (unsigned char) *3, MSGTYPE_I2C_DBG, (void *) error_buf);
442
        i2c_pdata->slave_error_count = 0;
443
    }
444
}
445
 
446
unsigned char i2c_master_busy() {
447
    if (i2c_pdata->master_state == I2C_MASTER_IDLE) {
448
        return 0;
449
    } else {
450
        return 1;
451
    }
452
}