Subversion Repositories Code-Repo

Rev

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