Subversion Repositories Code-Repo

Rev

Rev 282 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
281 Kevin 1
#include "defines.h"
2
#include "I2C1.h"
3
 
4
extern I2C1_DATA i2c_data;
5
 
6
// Set up the data structures for the base_I2C.code
7
// Should be called once before any i2c routines are called
8
void I2C1_Init(void) {
282 Kevin 9
    I2C_1_CLK_TRIS = 1;
10
    I2C_1_DAT_TRIS = 1;
11
 
281 Kevin 12
    i2c_data.buffer_in_len = 0;
13
    i2c_data.buffer_in_read_ind = 0;
14
    i2c_data.buffer_in_write_ind = 0;
15
 
16
    i2c_data.operating_state = I2C_IDLE;
17
    i2c_data.return_status = 0;
18
 
19
    i2c_data.master_dest_addr = 0;
20
    i2c_data.master_status = I2C_MASTER_IDLE;
21
 
22
    // Enable I2C interrupt
23
    PIE1bits.SSP1IE = 1;
24
}
25
 
26
// Setup the PIC to operate as a master.
27
void I2C1_Configure_Master(uint8_t speed) {
28
    SSP1STAT = 0x0;
29
    SSP1CON1 = 0x0;
30
    SSP1CON2 = 0x0;
31
    SSP1CON3 = 0x0;
32
    SSP1CON1bits.SSPM = 0x8; // I2C Master Mode
33
    if (speed == 0x01) {
34
        SSP1ADD = 0x13;         // Operate at 400KHz (32MHz)
35
        SSP1STATbits.SMP = 1;    // Disable Slew Rate Control
36
    } else if (speed == 0x02) {
37
        SSP1ADD = 0x07;         // Operate at 1Mhz (32Mhz)
38
        SSP1STATbits.SMP = 1;    // Disable Slew Rate Control
39
    } else {
40
        SSP1ADD = 0x4F;         // Operate at 100KHz (32MHz)
41
        SSP1STATbits.SMP = 0;    // Enable Slew Rate Control
42
    }
43
    SSP1CON1bits.SSPEN = 1;  // Enable MSSP1 Module
44
}
45
 
46
// Sends length number of bytes in msg to specified address (no R/W bit)
47
void I2C1_Master_Send(uint8_t address, uint8_t length, uint8_t *msg) {
48
    if (length == 0)
49
        return;
50
 
51
    // Copy message to send into buffer and save length/address
52
    for (uint8_t i = 0; i < length; i++) {
53
        i2c_data.buffer_in[i] = msg[i];
54
    }
55
    i2c_data.buffer_in_len = length;
56
    i2c_data.master_dest_addr = address;
57
    i2c_data.buffer_in_read_ind = 0;
58
    i2c_data.buffer_in_write_ind = 0;
59
 
60
    // Change status to 'next' operation
61
    i2c_data.operating_state = I2C_SEND_ADDR;
62
    i2c_data.master_status = I2C_MASTER_SEND;
63
 
64
    // Generate start condition
65
    SSP1CON2bits.SEN = 1;
66
}
67
 
68
// Reads length number of bytes from address (no R/W bit)
69
void I2C1_Master_Recv(uint8_t address, uint8_t length) {
70
    if (length == 0)
71
        return;
72
 
73
    // Save length and address to get data from
74
    i2c_data.buffer_in_len = length;
75
    i2c_data.master_dest_addr = address;
76
    i2c_data.buffer_in_read_ind = 0;
77
    i2c_data.buffer_in_write_ind = 0;
78
 
79
    // Change status to 'next' operation
80
    i2c_data.operating_state = I2C_SEND_ADDR;
81
    i2c_data.master_status = I2C_MASTER_RECV;
82
 
83
    // Generate start condition
84
    SSP1CON2bits.SEN = 1;
85
}
86
 
87
// Writes msg to address then reads length number of bytes from address
88
void I2C1_Master_Restart(uint8_t address, uint8_t msg, uint8_t length) {
89
    uint8_t c;
90
    if (length == 0) {
91
        c = msg;
92
        I2C1_Master_Send(address, 1, &c);
93
        return;
94
    }
95
 
96
    // Save length and address to get data from
97
    i2c_data.buffer_in[0] = msg;
98
    i2c_data.buffer_in_len = length;
99
    i2c_data.master_dest_addr = address;
100
    i2c_data.buffer_in_read_ind = 0;
101
    i2c_data.buffer_in_write_ind = 0;
102
 
103
    // Change status to 'next' operation
104
    i2c_data.operating_state = I2C_SEND_ADDR;
105
    i2c_data.master_status = I2C_MASTER_RESTART;
106
 
107
    // Generate start condition
108
    SSP1CON2bits.SEN = 1;
109
}
110
 
111
void I2C1_Interrupt_Handler() {
112
    // If we are in the middle of sending data
113
    if (i2c_data.master_status == I2C_MASTER_SEND) {
114
        switch (i2c_data.operating_state) {
115
            case I2C_IDLE:
116
                break;
117
            case I2C_SEND_ADDR:
118
                // Send the address with read bit set
119
                i2c_data.operating_state = I2C_CHECK_ACK_SEND;
120
                SSP1BUF = (i2c_data.master_dest_addr << 1) | 0x0;
121
                break;
122
            case I2C_CHECK_ACK_SEND:
123
                // Check if ACK is received or not
124
                if (!SSP1CON2bits.ACKSTAT) {
125
                    // If an ACK is received, send next byte of data
126
                    if (i2c_data.buffer_in_read_ind < i2c_data.buffer_in_len) {
127
                        SSP1BUF = i2c_data.buffer_in[i2c_data.buffer_in_read_ind];
128
                        i2c_data.buffer_in_read_ind++;
129
                    } else {
130
                        // If no more data is to be sent, send stop bit
131
                        i2c_data.operating_state = I2C_IDLE;
132
                        SSP1CON2bits.PEN = 1;
133
                        i2c_data.master_status = I2C_MASTER_IDLE;
134
                        i2c_data.return_status = I2C_SEND_OK;
135
                    }
136
                } else {
137
                    // If a NACK is received, stop transmission and send error
138
                    i2c_data.operating_state = I2C_IDLE;
139
                    SSP1CON2bits.PEN = 1;
140
                    i2c_data.master_status = I2C_MASTER_IDLE;
141
                    i2c_data.return_status = I2C_SEND_FAIL;
142
                }
143
                break;
144
        }
145
    // If we are in the middle of receiving data
146
    } else if (i2c_data.master_status == I2C_MASTER_RECV) {
147
        switch (i2c_data.operating_state) {
148
            case I2C_IDLE:
149
                break;
150
            case I2C_SEND_ADDR:
151
                // Send address with write bit set
152
                i2c_data.operating_state = I2C_CHECK_ACK_RECV;
153
                uint8_t tmp = (i2c_data.master_dest_addr << 1);
154
                tmp |= 0x01;
155
                SSP1BUF = tmp;
156
                break;
157
            case I2C_CHECK_ACK_RECV:
158
                // Check if ACK is received
159
                if (!SSP1CON2bits.ACKSTAT) {
160
                    // If an ACK is received, set module to receive 1 byte of data
161
                    i2c_data.operating_state = I2C_RCV_DATA;
162
                    SSP1CON2bits.RCEN = 1;
163
                } else {
164
                    // If a NACK is received, stop transmission and send error
165
                    i2c_data.operating_state = I2C_IDLE;
166
                    SSP1CON2bits.PEN = 1;
167
                    i2c_data.master_status = I2C_MASTER_IDLE;
168
                    i2c_data.return_status = I2C_RECV_FAIL;
169
                }
170
                break;
171
            case I2C_RCV_DATA:
172
                // On receive, save byte into buffer
173
                // TODO: Handle I2C buffer overflow
174
                i2c_data.buffer_in[i2c_data.buffer_in_write_ind] = SSP1BUF;
175
                i2c_data.buffer_in_write_ind++;
176
                if (i2c_data.buffer_in_write_ind < i2c_data.buffer_in_len) {
177
                    // If we still need to read, send an ACK to the slave
178
                    i2c_data.operating_state = I2C_REQ_DATA;
179
                    SSP1CON2bits.ACKDT = 0;  // ACK
180
                    SSP1CON2bits.ACKEN = 1;
181
                } else {
182
                    // If we are done reading, send an NACK to the slave
183
                    i2c_data.operating_state = I2C_SEND_STOP;
184
                    SSP1CON2bits.ACKDT = 1;  // NACK
185
                    SSP1CON2bits.ACKEN = 1;
186
                }
187
                break;
188
            case I2C_REQ_DATA:
189
                // Set module to receive one byte of data
190
                i2c_data.operating_state = I2C_RCV_DATA;
191
                SSP1CON2bits.RCEN = 1;
192
                break;
193
            case I2C_SEND_STOP:
194
                // Send the stop bit and copy message to send to Main()
195
                i2c_data.operating_state = I2C_IDLE;
196
                SSP1CON2bits.PEN = 1;
197
                i2c_data.master_status = I2C_MASTER_IDLE;
198
                i2c_data.return_status = I2C_RECV_OK;
199
                break;
200
        }
201
    } else if (i2c_data.master_status == I2C_MASTER_RESTART) {
202
        switch (i2c_data.operating_state) {
203
            case I2C_IDLE:
204
                break;
205
            case I2C_SEND_ADDR:
206
                // Send the address with read bit set
207
                i2c_data.operating_state = I2C_CHECK_ACK_SEND;
208
                SSP1BUF = (i2c_data.master_dest_addr << 1) | 0x0;
209
                break;
210
            case I2C_CHECK_ACK_SEND:
211
                // Check if ACK is received or not
212
                if (!SSP1CON2bits.ACKSTAT) {
213
                    // If an ACK is received, send first byte of data
214
                    SSP1BUF = i2c_data.buffer_in[0];
215
                    i2c_data.operating_state = I2C_CHECK_ACK_RESTART;
216
                } else {
217
                    // If a NACK is received, stop transmission and send error
218
                    i2c_data.operating_state = I2C_IDLE;
219
                    SSP1CON2bits.PEN = 1;
220
                    i2c_data.master_status = I2C_MASTER_IDLE;
221
                    i2c_data.return_status = I2C_SEND_FAIL;
222
                }
223
                break;
224
            case I2C_CHECK_ACK_RESTART:
225
                if (!SSP1CON2bits.ACKSTAT) {
226
                    SSP1CON2bits.RSEN = 1;
227
                    i2c_data.operating_state = I2C_SEND_ADDR_2;
228
                } else {
229
                    // If a NACK is received, stop transmission and send error
230
                    i2c_data.operating_state = I2C_IDLE;
231
                    SSP1CON2bits.PEN = 1;
232
                    i2c_data.master_status = I2C_MASTER_IDLE;
233
                    i2c_data.return_status = I2C_SEND_FAIL;
234
                }
235
                break;
236
            case I2C_SEND_ADDR_2:
237
                // Send the address with read bit set
238
                i2c_data.operating_state = I2C_CHECK_ACK_RECV;
239
                uint8_t tmp = (i2c_data.master_dest_addr << 1);
240
                tmp |= 0x01;
241
                SSP1BUF = tmp;
242
                break;
243
            case I2C_CHECK_ACK_RECV:
244
                // Check if ACK is received
245
                if (!SSP1CON2bits.ACKSTAT) {
246
                    // If an ACK is received, set module to receive 1 byte of data
247
                    i2c_data.operating_state = I2C_RCV_DATA;
248
                    SSP1CON2bits.RCEN = 1;
249
                } else {
250
                    // If a NACK is received, stop transmission and send error
251
                    i2c_data.operating_state = I2C_IDLE;
252
                    SSP1CON2bits.PEN = 1;
253
                    i2c_data.master_status = I2C_MASTER_IDLE;
254
                    i2c_data.return_status = I2C_RECV_FAIL;
255
                }
256
                break;
257
            case I2C_RCV_DATA:
258
                // On receive, save byte into buffer
259
                // TODO: Handle I2C buffer overflow
260
                i2c_data.buffer_in[i2c_data.buffer_in_write_ind] = SSP1BUF;
261
                i2c_data.buffer_in_write_ind++;
262
                if (i2c_data.buffer_in_write_ind < i2c_data.buffer_in_len) {
263
                    // If we still need to read, send an ACK to the slave
264
                    i2c_data.operating_state = I2C_REQ_DATA;
265
                    SSP1CON2bits.ACKDT = 0;  // ACK
266
                    SSP1CON2bits.ACKEN = 1;
267
                } else {
268
                    // If we are done reading, send an NACK to the slave
269
                    i2c_data.operating_state = I2C_SEND_STOP;
270
                    SSP1CON2bits.ACKDT = 1;  // NACK
271
                    SSP1CON2bits.ACKEN = 1;
272
                }
273
                break;
274
            case I2C_REQ_DATA:
275
                // Set module to receive one byte of data
276
                i2c_data.operating_state = I2C_RCV_DATA;
277
                SSP1CON2bits.RCEN = 1;
278
                break;
279
            case I2C_SEND_STOP:
280
                // Send the stop bit
281
                i2c_data.operating_state = I2C_IDLE;
282
                SSP1CON2bits.PEN = 1;
283
                i2c_data.master_status = I2C_MASTER_IDLE;
284
                i2c_data.return_status = I2C_RECV_OK;
285
                break;
286
        }
287
    }
288
}
289
 
290
/* Returns 0 if I2C module is currently busy, otherwise returns status code */
291
uint8_t I2C1_Get_Status() {
292
//    if (i2c_data.operating_mode == I2C_MODE_MASTER) {
293
        if (i2c_data.master_status != I2C_MASTER_IDLE || i2c_data.buffer_in_len == 0) {
294
            return 0;
295
        } else {
296
            return i2c_data.return_status;
297
        }
298
}
299
 
300
uint8_t I2C1_Buffer_Len() {
301
    return i2c_data.buffer_in_len;
302
}
303
 
304
/* Returns 0 if I2C module is currently busy, otherwise returns buffer length */
305
uint8_t I2C1_Read_Buffer(uint8_t *buffer) {
306
    uint8_t i = 0;
307
    while (i2c_data.buffer_in_len != 0) {
308
        buffer[i] = i2c_data.buffer_in[i2c_data.buffer_in_read_ind];
309
        i++;
310
        if (i2c_data.buffer_in_read_ind == MAXI2C1BUF-1) {
311
            i2c_data.buffer_in_read_ind = 0;
312
        } else {
313
            i2c_data.buffer_in_read_ind++;
314
        }
315
        i2c_data.buffer_in_len--;
316
    }
317
    return i;
318
}