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