Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

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