Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
234 Kevin 1
#include "defines.h"
2
#include "I2C1.h"
3
 
4
static I2C1_DATA *i2c_data_p;
5
 
6
// Initialize the data structures, should be called once before any I2C routines are called
7
void I2C1_Init(I2C1_DATA *data, uint8_t speed, uint8_t address) {
8
    i2c_data_p = data;
9
 
10
    i2c_data_p->buffer_in_len = 0;
11
    i2c_data_p->buffer_in_read_ind = 0;
12
    i2c_data_p->buffer_in_write_ind = 0;
13
 
14
    i2c_data_p->buffer_out_ind = 0;
15
    i2c_data_p->buffer_out_len = 0;
16
 
17
    i2c_data_p->operating_state = I2C1_IDLE;
18
    i2c_data_p->return_status = 0;
19
 
20
    i2c_data_p->slave_in_last_byte = 0;
21
    i2c_data_p->slave_sending_data = 0;
22
 
23
    i2c_data_p->master_dest_addr = 0;
24
    i2c_data_p->master_status = I2C1_MASTER_IDLE;
25
 
26
    INTDisableInterrupts();
27
 
28
    // Enable the I2C module and set the clock stretch enable bit
29
    // Note: Automatically overrides any other pin settings
30
    I2C1CONSET = 0x00008040;
31
    I2C1ADD = address;
32
    if (!speed) I2C1BRG = 0x05A;    // Operate at 400kHZ (80MHz)
33
    else        I2C1BRG = 0x186;    // Operate at 100kHZ (80MHz)
34
    IFS0CLR = 0xE0000000;   // Clear any existing events
35
    IPC6CLR = 0x00001F00;   // Reset priority levels
36
    IPC6SET = 0x00001500;   // Set IPL=5, Subpriority 1
37
    IEC0SET = 0xE0000000;   // Enable I2C1 interrupts
38
 
39
    INTEnableInterrupts();
40
}
41
 
42
// Sends length number of bytes in msg to specified address (no R/W bit)
43
void I2C1_Master_Send(uint8_t address, uint8_t *msg, uint32_t length) {
44
    uint32_t 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_data_p->buffer_in[i] = msg[i];
51
    }
52
    i2c_data_p->buffer_in_len = length;
53
    i2c_data_p->master_dest_addr = address;
54
    i2c_data_p->buffer_in_read_ind = 0;
55
    i2c_data_p->buffer_in_write_ind = 0;
56
 
57
    // Change status to 'next' operation
58
    i2c_data_p->operating_state = I2C1_SEND_ADDR;
59
    i2c_data_p->master_status = I2C1_MASTER_SEND;
60
 
61
    // Generate start condition
62
    I2C1CONbits.SEN = 1;
63
}
64
 
65
// Reads length number of bytes from address (no R/W bit)
66
void I2C1_Master_Recv(uint8_t address, uint32_t length) {
67
    if (length == 0)
68
        return;
69
 
70
    // Save length and address to get data from
71
    i2c_data_p->buffer_in_len = length;
72
    i2c_data_p->master_dest_addr = address;
73
    i2c_data_p->buffer_in_read_ind = 0;
74
    i2c_data_p->buffer_in_write_ind = 0;
75
 
76
    // Change status to 'next' operation
77
    i2c_data_p->operating_state = I2C1_SEND_ADDR;
78
    i2c_data_p->master_status = I2C1_MASTER_RECV;
79
 
80
    // Generate start condition
81
    I2C1CONbits.SEN = 1;
82
}
83
 
84
// Writes msg to address then reads length number of bytes from address
85
void I2C1_Master_Restart(uint8_t address, uint8_t msg, uint32_t length) {
86
    uint8_t c;
87
    if (length == 0) {
88
        c = msg;
89
        I2C1_Master_Send(address, &c, 1);
90
        return;
91
    }
92
 
93
    // Save length and address to get data from
94
    i2c_data_p->buffer_in[0] = msg;
95
    i2c_data_p->buffer_in_len = length;
96
    i2c_data_p->master_dest_addr = address;
97
    i2c_data_p->buffer_in_read_ind = 0;
98
    i2c_data_p->buffer_in_write_ind = 0;
99
 
100
    // Change status to 'next' operation
101
    i2c_data_p->operating_state = I2C1_SEND_ADDR;
102
    i2c_data_p->master_status = I2C1_MASTER_RESTART;
103
 
104
    // Generate start condition
105
    I2C1CONbits.SEN = 1;
106
}
107
 
108
void __ISR(_I2C_1_VECTOR, ipl5) __I2C_1_Interrupt_Handler(void) {
109
    // Bus collision event
110
    if (IFS0bits.I2C1BIF) {
111
        // This should be handled at some point
112
        IFS0CLR = 0x20000000;
113
    }
114
    // Slave event
115
    if (IFS0bits.I2C1SIF) {
116
        I2C1_Interrupt_Slave();
117
        IFS0CLR = 0x40000000;
118
    }
119
    // Master event
120
    if (IFS0bits.I2C1MIF) {
121
        I2C1_Interrupt_Master();
122
        IFS0CLR = 0x80000000;
123
    }
124
}
125
 
126
// An internal subroutine used in the master version of the i2c_interrupt_handler
127
void I2C1_Interrupt_Master() {
128
 
129
    /* The PIC32 family has different master interrupts than the PIC8 family
130
     * Master mode operations that generate a slave interrupt are:
131
     * 1. Start condition
132
     * 2. Repeated start sequence
133
     * 3. Stop condition
134
     * 4. Data transfer byte received
135
     * 5. During a send ACK or NACK sequence to slave
136
     * 6. Data transfer byte transmitted
137
     * 7. During a slave-detected stop
138
     */
139
 
140
    // If we are in the middle of sending data
141
    if (i2c_data_p->master_status == I2C1_MASTER_SEND) {
142
        switch (i2c_data_p->operating_state) {
143
            case I2C1_IDLE:
144
                break;
145
            case I2C1_SEND_ADDR:
146
                // Send the address with read bit set
147
                i2c_data_p->operating_state = I2C1_CHECK_ACK_SEND;
148
                I2C1TRN = (i2c_data_p->master_dest_addr << 1) | 0x0;
149
                break;
150
            case I2C1_CHECK_ACK_SEND:
151
                // Check if ACK is received or not
152
                if (!I2C1STATbits.ACKSTAT) {
153
                    // If an ACK is received, send next byte of data
154
                    if (i2c_data_p->buffer_in_read_ind < i2c_data_p->buffer_in_len) {
155
                        I2C1TRN = i2c_data_p->buffer_in[i2c_data_p->buffer_in_read_ind];
156
                        i2c_data_p->buffer_in_read_ind++;
157
                    } else {
158
                        // If no more data is to be sent, send stop bit
159
                        i2c_data_p->operating_state = I2C1_IDLE;
160
                        I2C1CONbits.PEN = 1;
161
                        i2c_data_p->master_status = I2C1_MASTER_IDLE;
162
                        i2c_data_p->return_status = I2C1_SEND_OK;
163
                    }
164
                } else {
165
                    // If a NACK is received, stop transmission and send error
166
                    i2c_data_p->operating_state = I2C1_IDLE;
167
                    I2C1CONbits.PEN = 1;
168
                    i2c_data_p->master_status = I2C1_MASTER_IDLE;
169
                    i2c_data_p->return_status = I2C1_SEND_FAIL;
170
                }
171
                break;
172
        }
173
    // If we are in the middle of receiving data
174
    } else if (i2c_data_p->master_status == I2C1_MASTER_RECV) {
175
        switch (i2c_data_p->operating_state) {
176
            case I2C1_IDLE:
177
                break;
178
            case I2C1_SEND_ADDR:
179
                // Send address with write bit set
180
                i2c_data_p->operating_state = I2C1_CHECK_ACK_RECV;
181
                I2C1TRN = (i2c_data_p->master_dest_addr << 1) | 0x1;
182
                break;
183
            case I2C1_CHECK_ACK_RECV:
184
                // Check if ACK is received
185
                if (!I2C1STATbits.ACKSTAT) {
186
                    // If an ACK is received, set module to receive 1 byte of data
187
                    i2c_data_p->operating_state = I2C1_RCV_DATA;
188
                    I2C1CONbits.RCEN = 1;
189
                } else {
190
                    // If a NACK is received, stop transmission and send error
191
                    i2c_data_p->operating_state = I2C1_IDLE;
192
                    I2C1CONbits.PEN = 1;
193
                    i2c_data_p->master_status = I2C1_MASTER_IDLE;
194
                    i2c_data_p->return_status = I2C1_RECV_FAIL;
195
                }
196
                break;
197
            case I2C1_RCV_DATA:
198
                // On receive, save byte into buffer
199
                // TODO: Handle I2C buffer overflow
200
                i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = I2C1RCV;
201
                i2c_data_p->buffer_in_write_ind++;
202
                if (i2c_data_p->buffer_in_write_ind < i2c_data_p->buffer_in_len) {
203
                    // If we still need to read, send an ACK to the slave
204
                    i2c_data_p->operating_state = I2C1_REQ_DATA;
205
                    I2C1CONbits.ACKDT = 0;  // ACK
206
                    I2C1CONbits.ACKEN = 1;
207
                } else {
208
                    // If we are done reading, send an NACK to the slave
209
                    i2c_data_p->operating_state = I2C1_SEND_STOP;
210
                    I2C1CONbits.ACKDT = 1;  // NACK
211
                    I2C1CONbits.ACKEN = 1;
212
                }
213
                break;
214
            case I2C1_REQ_DATA:
215
                // Set module to receive one byte of data
216
                i2c_data_p->operating_state = I2C1_RCV_DATA;
217
                I2C1CONbits.RCEN = 1;
218
                break;
219
            case I2C1_SEND_STOP:
220
                // Send the stop bit and copy message to send to Main()
221
                i2c_data_p->operating_state = I2C1_IDLE;
222
                I2C1CONbits.PEN = 1;
223
                i2c_data_p->master_status = I2C1_MASTER_IDLE;
224
                i2c_data_p->return_status = I2C1_RECV_OK;
225
                break;
226
        }
227
    } else if (i2c_data_p->master_status == I2C1_MASTER_RESTART) {
228
        switch (i2c_data_p->operating_state) {
229
            case I2C1_IDLE:
230
                break;
231
            case I2C1_SEND_ADDR:
232
                // Send the address with read bit set
233
                i2c_data_p->operating_state = I2C1_CHECK_ACK_SEND;
234
                I2C1TRN = (i2c_data_p->master_dest_addr << 1) | 0x0;
235
                break;
236
            case I2C1_CHECK_ACK_SEND:
237
                // Check if ACK is received or not
238
                if (!I2C1STATbits.ACKSTAT) {
239
                    // If an ACK is received, send first byte of data
240
                    I2C1TRN = i2c_data_p->buffer_in[0];
241
                    i2c_data_p->operating_state = I2C1_CHECK_ACK_RESTART;
242
                } else {
243
                    // If a NACK is received, stop transmission and send error
244
                    i2c_data_p->operating_state = I2C1_IDLE;
245
                    I2C1CONbits.PEN = 1;
246
                    i2c_data_p->master_status = I2C1_MASTER_IDLE;
247
                    i2c_data_p->return_status = I2C1_SEND_FAIL;
248
                }
249
                break;
250
            case I2C1_CHECK_ACK_RESTART:
251
                if (!I2C1STATbits.ACKSTAT) {
252
                    I2C1CONbits.RSEN = 1;
253
                    i2c_data_p->operating_state = I2C1_SEND_ADDR_2;
254
                } else {
255
                    // If a NACK is received, stop transmission and send error
256
                    i2c_data_p->operating_state = I2C1_IDLE;
257
                    I2C1CONbits.PEN = 1;
258
                    i2c_data_p->master_status = I2C1_MASTER_IDLE;
259
                    i2c_data_p->return_status = I2C1_SEND_FAIL;
260
                }
261
                break;
262
            case I2C1_SEND_ADDR_2:
263
                // Send the address with read bit set
264
                i2c_data_p->operating_state = I2C1_CHECK_ACK_RECV;
265
                I2C1TRN = (i2c_data_p->master_dest_addr << 1) | 0x1;
266
                break;
267
            case I2C1_CHECK_ACK_RECV:
268
                // Check if ACK is received
269
                if (!I2C1STATbits.ACKSTAT) {
270
                    // If an ACK is received, set module to receive 1 byte of data
271
                    i2c_data_p->operating_state = I2C1_RCV_DATA;
272
                    I2C1CONbits.RCEN = 1;
273
                } else {
274
                    // If a NACK is received, stop transmission and send error
275
                    i2c_data_p->operating_state = I2C1_IDLE;
276
                    I2C1CONbits.PEN = 1;
277
                    i2c_data_p->master_status = I2C1_MASTER_IDLE;
278
                    i2c_data_p->return_status = I2C1_RECV_FAIL;
279
                }
280
                break;
281
            case I2C1_RCV_DATA:
282
                // On receive, save byte into buffer
283
                // TODO: Handle I2C buffer overflow
284
                i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = I2C1RCV;
285
                i2c_data_p->buffer_in_write_ind++;
286
                if (i2c_data_p->buffer_in_write_ind < i2c_data_p->buffer_in_len) {
287
                    // If we still need to read, send an ACK to the slave
288
                    i2c_data_p->operating_state = I2C1_REQ_DATA;
289
                    I2C1CONbits.ACKDT = 0;  // ACK
290
                    I2C1CONbits.ACKEN = 1;
291
                } else {
292
                    // If we are done reading, send an NACK to the slave
293
                    i2c_data_p->operating_state = I2C1_SEND_STOP;
294
                    I2C1CONbits.ACKDT = 1;  // NACK
295
                    I2C1CONbits.ACKEN = 1;
296
                }
297
                break;
298
            case I2C1_REQ_DATA:
299
                // Set module to receive one byte of data
300
                i2c_data_p->operating_state = I2C1_RCV_DATA;
301
                I2C1CONbits.RCEN = 1;
302
                break;
303
            case I2C1_SEND_STOP:
304
                // Send the stop bit and copy message to send to Main()
305
                i2c_data_p->operating_state = I2C1_IDLE;
306
                I2C1CONbits.PEN = 1;
307
                i2c_data_p->master_status = I2C1_MASTER_IDLE;
308
                i2c_data_p->return_status = I2C1_RECV_OK;
309
                break;
310
        }
311
    }
312
}
313
 
314
void I2C1_Interrupt_Slave() {
315
    // !!WARNING!! THIS CODE DOES -NOT- HAVE ANY ERROR HANDLING !!
316
    // TODO: Add error handling to this interrupt function
317
 
318
    /* The PIC32 family has different slave interrupts than the PIC8 family
319
     * Slave mode operations that generate a slave interrupt are:
320
     * 1. Detection of a valid device address (including general call)
321
     * 2. Reception of data
322
     * 3. Request to transmit data
323
     */
324
 
325
    uint8_t received_data;
326
    uint8_t data_read_from_buffer = 0;
327
    uint8_t data_written_to_buffer = 0;
328
    uint8_t overrun_error = 0;
329
 
330
    // Clear SSPOV (overflow bit)
331
    if (I2C1STATbits.I2COV == 1) {
332
        I2C1STATbits.I2COV = 0;
333
        overrun_error = 1;
334
        i2c_data_p->return_status = I2C1_ERR_OVERRUN;
335
    }
336
 
337
    // Read SPPxBUF if it is full
338
    if (I2C1STATbits.RBF == 1) {
339
        received_data = I2C1RCV;
340
        data_read_from_buffer = 1;
341
    }
342
 
343
    if (!overrun_error) {
344
        if (I2C1STATbits.R_W == 0) {
345
            // Slave is receiving data
346
            i2c_data_p->buffer_in[i2c_data_p->buffer_in_write_ind] = received_data;
347
            if (i2c_data_p->buffer_in_write_ind == MAXI2C1BUF - 1) {
348
                i2c_data_p->buffer_in_write_ind = 0;
349
            } else {
350
                i2c_data_p->buffer_in_write_ind++;
351
            }
352
            if (i2c_data_p->buffer_in_len < MAXI2C1BUF - 1) {
353
                i2c_data_p->buffer_in_len++;
354
            }
355
            i2c_data_p->slave_in_last_byte = received_data;
356
            i2c_data_p->return_status = I2C1_RECV_OK;
357
        } else {
358
            // Slave is returning data
359
            if (!i2c_data_p->slave_sending_data) {
360
                // If we are not currently sending data, figure out what to reply with
361
                if (I2C1_Process_Request(i2c_data_p->slave_in_last_byte)) {
362
                    // Data exists to be returned, send first byte
363
                    I2C1TRN = i2c_data_p->buffer_out[0];
364
                    data_written_to_buffer = 1;
365
                    i2c_data_p->buffer_out_ind = 1;
366
                    i2c_data_p->slave_sending_data = 1;
367
                } else {
368
                    // Unknown request, fill rest of request with 0s
369
                    I2C1TRN = 0x0;
370
                    data_written_to_buffer = 1;
371
                    i2c_data_p->slave_sending_data = 0;
372
                    i2c_data_p->return_status = I2C1_SEND_FAIL;
373
                }
374
            } else {
375
                // Sending remaining data back to master
376
                if (i2c_data_p->buffer_out_ind < i2c_data_p->buffer_out_len) {
377
                    I2C1TRN = i2c_data_p->buffer_out[i2c_data_p->buffer_out_ind];
378
                    data_written_to_buffer = 1;
379
                    i2c_data_p->buffer_out_ind++;
380
                } else {
381
                    // Nothing left to send, fill rest of request with 0s
382
                    I2C1TRN = 0x0;
383
                    data_written_to_buffer = 1;
384
                    i2c_data_p->slave_sending_data = 0;
385
                    i2c_data_p->return_status = I2C1_SEND_OK;
386
                }
387
            }
388
        }
389
    }
390
 
391
    // Release the clock stretching bit (if we should)
392
    if (data_read_from_buffer || data_written_to_buffer) {
393
        // Release the clock
394
        if (I2C1CONbits.SCLREL == 0) {
395
            I2C1CONbits.SCLREL = 1;
396
        }
397
    }
398
}
399
 
400
/* Returns 0 if I2C module is currently busy, otherwise returns status code */
401
uint8_t I2C1_Get_Status() {
402
        if (i2c_data_p->master_status != I2C1_MASTER_IDLE ||
403
                i2c_data_p->buffer_in_len == 0) {
404
            return 0;
405
        } else {
406
            return i2c_data_p->return_status;
407
        }
408
}
409
 
410
uint8_t I2C1_Buffer_Len() {
411
    return i2c_data_p->buffer_in_len;
412
}
413
 
414
/* Returns 0 if I2C module is currently busy, otherwise returns buffer length */
415
uint8_t I2C1_Read_Buffer(uint8_t *buffer) {
416
    uint32_t i = 0;
417
    while (i2c_data_p->buffer_in_len != 0) {
418
        buffer[i] = i2c_data_p->buffer_in[i2c_data_p->buffer_in_read_ind];
419
        i++;
420
        if (i2c_data_p->buffer_in_read_ind == MAXI2C1BUF-1) {
421
            i2c_data_p->buffer_in_read_ind = 0;
422
        } else {
423
            i2c_data_p->buffer_in_read_ind++;
424
        }
425
        i2c_data_p->buffer_in_len--;
426
    }
427
    return i;
428
}
429
 
430
/* Put data to be returned here */
431
uint8_t I2C1_Process_Request(uint8_t c) {
432
    uint8_t ret = 0;
433
    switch (c) {
434
        case 0x01:
435
            i2c_data_p->buffer_out[0] = 0x12;
436
            i2c_data_p->buffer_out_len = 1;
437
            ret = 1;
438
            break;
439
        case 0x02:
440
            i2c_data_p->buffer_out[0] = 0x34;
441
            i2c_data_p->buffer_out[1] = 0x56;
442
            i2c_data_p->buffer_out_len = 2;
443
            ret = 1;
444
            break;
445
    }
446
    return ret;
447
}