Subversion Repositories Code-Repo

Rev

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