1 | /**
|
2 | I2C1 Generated Driver File
|
3 |
|
4 | @Company
|
5 | Microchip Technology Inc.
|
6 |
|
7 | @File Name
|
8 | i2c1.c
|
9 |
|
10 | @Summary
|
11 | This is the generated header file for the I2C1 driver using MPLAB(c) Code Configurator
|
12 |
|
13 | @Description
|
14 | This header file provides APIs for driver for I2C1.
|
15 | Generation Information :
|
16 | Product Revision : MPLAB(c) Code Configurator - 3.15.0
|
17 | Device : PIC16F18854
|
18 | Driver Version : 2.00
|
19 | The generated drivers are tested against the following:
|
20 | Compiler : XC8 1.35
|
21 | MPLAB : MPLAB X 3.20
|
22 | */
|
23 |
|
24 | /*
|
25 | (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this
|
26 | software and any derivatives exclusively with Microchip products.
|
27 |
|
28 | THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
|
29 | EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
|
30 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
|
31 | PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
|
32 | WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
|
33 |
|
34 | IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
|
35 | INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
|
36 | WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
|
37 | BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
|
38 | FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
|
39 | ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
40 | THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
41 |
|
42 | MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
|
43 | TERMS.
|
44 | */
|
45 |
|
46 | /**
|
47 | Section: Included Files
|
48 | */
|
49 |
|
50 | #include "i2c1.h"
|
51 |
|
52 | /**
|
53 | I2C Driver Queue Status Type
|
54 |
|
55 | @Summary
|
56 | Defines the type used for the transaction queue status.
|
57 |
|
58 | @Description
|
59 | This defines type used to keep track of the queue status.
|
60 | */
|
61 |
|
62 | typedef union
|
63 | {
|
64 | struct
|
65 | {
|
66 | uint8_t full:1;
|
67 | uint8_t empty:1;
|
68 | uint8_t reserved:6;
|
69 | }s;
|
70 | uint8_t status;
|
71 | }I2C_TR_QUEUE_STATUS;
|
72 |
|
73 | /**
|
74 | I2C Driver Queue Entry Type
|
75 |
|
76 | @Summary
|
77 | Defines the object used for an entry in the i2c queue items.
|
78 |
|
79 | @Description
|
80 | This defines the object in the i2c queue. Each entry is a composed
|
81 | of a list of TRBs, the number of the TRBs and the status of the
|
82 | currently processed TRB.
|
83 | */
|
84 | typedef struct
|
85 | {
|
86 | uint8_t count; // a count of trb's in the trb list
|
87 | I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list; // pointer to the trb list
|
88 | I2C1_MESSAGE_STATUS *pTrFlag; // set with the error of the last trb sent.
|
89 | // if all trb's are sent successfully,
|
90 | // then this is I2C1_MESSAGE_COMPLETE
|
91 | } I2C_TR_QUEUE_ENTRY;
|
92 |
|
93 | /**
|
94 | I2C Master Driver Object Type
|
95 |
|
96 | @Summary
|
97 | Defines the object that manages the i2c master.
|
98 |
|
99 | @Description
|
100 | This defines the object that manages the sending and receiving of
|
101 | i2c master transactions.
|
102 | */
|
103 |
|
104 | typedef struct
|
105 | {
|
106 | /* Read/Write Queue */
|
107 | I2C_TR_QUEUE_ENTRY *pTrTail; // tail of the queue
|
108 | I2C_TR_QUEUE_ENTRY *pTrHead; // head of the queue
|
109 | I2C_TR_QUEUE_STATUS trStatus; // status of the last transaction
|
110 | uint8_t i2cDoneFlag; // flag to indicate the current
|
111 | // transaction is done
|
112 | uint8_t i2cErrors; // keeps track of errors
|
113 |
|
114 |
|
115 | } I2C_OBJECT ;
|
116 |
|
117 | /**
|
118 | I2C Master Driver State Enumeration
|
119 |
|
120 | @Summary
|
121 | Defines the different states of the i2c master.
|
122 |
|
123 | @Description
|
124 | This defines the different states that the i2c master
|
125 | used to process transactions on the i2c bus.
|
126 | */
|
127 |
|
128 | typedef enum
|
129 | {
|
130 | S_MASTER_IDLE,
|
131 | S_MASTER_RESTART,
|
132 | S_MASTER_SEND_ADDR,
|
133 | S_MASTER_SEND_DATA,
|
134 | S_MASTER_SEND_STOP,
|
135 | S_MASTER_ACK_ADDR,
|
136 | S_MASTER_RCV_DATA,
|
137 | S_MASTER_RCV_STOP,
|
138 | S_MASTER_ACK_RCV_DATA,
|
139 | S_MASTER_NOACK_STOP,
|
140 | S_MASTER_SEND_ADDR_10BIT_LSB,
|
141 | S_MASTER_10BIT_RESTART,
|
142 |
|
143 | } I2C_MASTER_STATES;
|
144 |
|
145 | /**
|
146 | Section: Macro Definitions
|
147 | */
|
148 |
|
149 | /* defined for I2C1 */
|
150 |
|
151 | #ifndef I2C1_CONFIG_TR_QUEUE_LENGTH
|
152 | #define I2C1_CONFIG_TR_QUEUE_LENGTH 1
|
153 | #endif
|
154 |
|
155 | #define I2C1_TRANSMIT_REG SSP1BUF // Defines the transmit register used to send data.
|
156 | #define I2C1_RECEIVE_REG SSP1BUF // Defines the receive register used to receive data.
|
157 |
|
158 | // The following control bits are used in the I2C state machine to manage
|
159 | // the I2C module and determine next states.
|
160 | #define I2C1_WRITE_COLLISION_STATUS_BIT SSP1CON1bits.WCOL // Defines the write collision status bit.
|
161 | #define I2C1_MODE_SELECT_BITS SSP1CON1bits.SSPM // I2C Master Mode control bit.
|
162 | #define I2C1_MASTER_ENABLE_CONTROL_BITS SSP1CON1bits.SSPEN // I2C port enable control bit.
|
163 |
|
164 | #define I2C1_START_CONDITION_ENABLE_BIT SSP1CON2bits.SEN // I2C START control bit.
|
165 | #define I2C1_REPEAT_START_CONDITION_ENABLE_BIT SSP1CON2bits.RSEN // I2C Repeated START control bit.
|
166 | #define I2C1_RECEIVE_ENABLE_BIT SSP1CON2bits.RCEN // I2C Receive enable control bit.
|
167 | #define I2C1_STOP_CONDITION_ENABLE_BIT SSP1CON2bits.PEN // I2C STOP control bit.
|
168 | #define I2C1_ACKNOWLEDGE_ENABLE_BIT SSP1CON2bits.ACKEN // I2C ACK start control bit.
|
169 | #define I2C1_ACKNOWLEDGE_DATA_BIT SSP1CON2bits.ACKDT // I2C ACK data control bit.
|
170 | #define I2C1_ACKNOWLEDGE_STATUS_BIT SSP1CON2bits.ACKSTAT // I2C ACK status bit.
|
171 |
|
172 | #define I2C1_7bit true
|
173 | /**
|
174 | Section: Local Functions
|
175 | */
|
176 |
|
177 | void I2C1_FunctionComplete(void);
|
178 | void I2C1_Stop(I2C1_MESSAGE_STATUS completion_code);
|
179 |
|
180 | /**
|
181 | Section: Local Variables
|
182 | */
|
183 |
|
184 | static I2C_TR_QUEUE_ENTRY i2c1_tr_queue[I2C1_CONFIG_TR_QUEUE_LENGTH];
|
185 | static I2C_OBJECT i2c1_object;
|
186 | static I2C_MASTER_STATES i2c1_state = S_MASTER_IDLE;
|
187 | static uint8_t i2c1_trb_count = 0;
|
188 |
|
189 | static I2C1_TRANSACTION_REQUEST_BLOCK *p_i2c1_trb_current = NULL;
|
190 | static I2C_TR_QUEUE_ENTRY *p_i2c1_current = NULL;
|
191 |
|
192 |
|
193 | /**
|
194 | Section: Driver Interface
|
195 | */
|
196 |
|
197 |
|
198 | void I2C1_Initialize(void)
|
199 | {
|
200 | i2c1_object.pTrHead = i2c1_tr_queue;
|
201 | i2c1_object.pTrTail = i2c1_tr_queue;
|
202 | i2c1_object.trStatus.s.empty = true;
|
203 | i2c1_object.trStatus.s.full = false;
|
204 |
|
205 | i2c1_object.i2cErrors = 0;
|
206 |
|
207 | // SMP High Speed; CKE disabled;
|
208 | SSP1STAT = 0x00;
|
209 | // SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C;
|
210 | SSP1CON1 = 0x28;
|
211 | // SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
|
212 | SSP1CON3 = 0x00;
|
213 | // Baud Rate Generator Value: SSPADD 3;
|
214 | //SSP1ADD = 0x03;
|
215 | SSP1ADD = 0x19;
|
216 |
|
217 | // clear the master interrupt flag
|
218 | PIR3bits.SSP1IF = 0;
|
219 | // enable the master interrupt
|
220 | PIE3bits.SSP1IE = 1;
|
221 |
|
222 | }
|
223 |
|
224 |
|
225 | uint8_t I2C1_ErrorCountGet(void)
|
226 | {
|
227 | uint8_t ret;
|
228 |
|
229 | ret = i2c1_object.i2cErrors;
|
230 | return ret;
|
231 | }
|
232 |
|
233 | void I2C1_ISR ( void )
|
234 | {
|
235 |
|
236 | static uint8_t *pi2c_buf_ptr;
|
237 | static uint16_t i2c_address = 0;
|
238 | static uint8_t i2c_bytes_left = 0;
|
239 | static uint8_t i2c_10bit_address_restart = 0;
|
240 |
|
241 | PIR3bits.SSP1IF = 0;
|
242 |
|
243 | // Check first if there was a collision.
|
244 | // If we have a Write Collision, reset and go to idle state */
|
245 | if(I2C1_WRITE_COLLISION_STATUS_BIT)
|
246 | {
|
247 | // clear the Write colision
|
248 | I2C1_WRITE_COLLISION_STATUS_BIT = 0;
|
249 | i2c1_state = S_MASTER_IDLE;
|
250 | *(p_i2c1_current->pTrFlag) = I2C1_MESSAGE_FAIL;
|
251 |
|
252 | // reset the buffer pointer
|
253 | p_i2c1_current = NULL;
|
254 |
|
255 | return;
|
256 | }
|
257 |
|
258 | /* Handle the correct i2c state */
|
259 | switch(i2c1_state)
|
260 | {
|
261 | case S_MASTER_IDLE: /* In reset state, waiting for data to send */
|
262 |
|
263 | if(i2c1_object.trStatus.s.empty != true)
|
264 | {
|
265 | // grab the item pointed by the head
|
266 | p_i2c1_current = i2c1_object.pTrHead;
|
267 | i2c1_trb_count = i2c1_object.pTrHead->count;
|
268 | p_i2c1_trb_current = i2c1_object.pTrHead->ptrb_list;
|
269 |
|
270 | i2c1_object.pTrHead++;
|
271 |
|
272 | // check if the end of the array is reached
|
273 | if(i2c1_object.pTrHead == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
|
274 | {
|
275 | // adjust to restart at the beginning of the array
|
276 | i2c1_object.pTrHead = i2c1_tr_queue;
|
277 | }
|
278 |
|
279 | // since we moved one item to be processed, we know
|
280 | // it is not full, so set the full status to false
|
281 | i2c1_object.trStatus.s.full = false;
|
282 |
|
283 | // check if the queue is empty
|
284 | if(i2c1_object.pTrHead == i2c1_object.pTrTail)
|
285 | {
|
286 | // it is empty so set the empty status to true
|
287 | i2c1_object.trStatus.s.empty = true;
|
288 | }
|
289 |
|
290 | // send the start condition
|
291 | I2C1_START_CONDITION_ENABLE_BIT = 1;
|
292 |
|
293 | // start the i2c request
|
294 | i2c1_state = S_MASTER_SEND_ADDR;
|
295 | }
|
296 |
|
297 | break;
|
298 |
|
299 | case S_MASTER_RESTART:
|
300 |
|
301 | /* check for pending i2c Request */
|
302 |
|
303 | // ... trigger a REPEATED START
|
304 | I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;
|
305 |
|
306 | // start the i2c request
|
307 | i2c1_state = S_MASTER_SEND_ADDR;
|
308 |
|
309 | break;
|
310 |
|
311 | case S_MASTER_SEND_ADDR_10BIT_LSB:
|
312 |
|
313 | if(I2C1_ACKNOWLEDGE_STATUS_BIT)
|
314 | {
|
315 | i2c1_object.i2cErrors++;
|
316 | I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
|
317 | }
|
318 | else
|
319 | {
|
320 | // Remove bit 0 as R/W is never sent here
|
321 | I2C1_TRANSMIT_REG = (i2c_address >> 1) & 0x00FF;
|
322 |
|
323 | // determine the next state, check R/W
|
324 | if(i2c_address & 0x01)
|
325 | {
|
326 | // if this is a read we must repeat start
|
327 | // the bus to perform a read
|
328 | i2c1_state = S_MASTER_10BIT_RESTART;
|
329 | }
|
330 | else
|
331 | {
|
332 | // this is a write continue writing data
|
333 | i2c1_state = S_MASTER_SEND_DATA;
|
334 | }
|
335 | }
|
336 |
|
337 | break;
|
338 |
|
339 | case S_MASTER_10BIT_RESTART:
|
340 |
|
341 | if(I2C1_ACKNOWLEDGE_STATUS_BIT)
|
342 | {
|
343 | i2c1_object.i2cErrors++;
|
344 | I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
|
345 | }
|
346 | else
|
347 | {
|
348 | // ACK Status is good
|
349 | // restart the bus
|
350 | I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;
|
351 |
|
352 | // fudge the address so S_MASTER_SEND_ADDR works correctly
|
353 | // we only do this on a 10-bit address resend
|
354 | i2c_address = 0x00F0 | ((i2c_address >> 8) & 0x0006);
|
355 |
|
356 | // set the R/W flag
|
357 | i2c_address |= 0x0001;
|
358 |
|
359 | // set the address restart flag so we do not change the address
|
360 | i2c_10bit_address_restart = 1;
|
361 |
|
362 | // Resend the address as a read
|
363 | i2c1_state = S_MASTER_SEND_ADDR;
|
364 | }
|
365 |
|
366 | break;
|
367 |
|
368 | case S_MASTER_SEND_ADDR:
|
369 |
|
370 | /* Start has been sent, send the address byte */
|
371 |
|
372 | /* Note:
|
373 | On a 10-bit address resend (done only during a 10-bit
|
374 | device read), the original i2c_address was modified in
|
375 | S_MASTER_10BIT_RESTART state. So the check if this is
|
376 | a 10-bit address will fail and a normal 7-bit address
|
377 | is sent with the R/W bit set to read. The flag
|
378 | i2c_10bit_address_restart prevents the address to
|
379 | be re-written.
|
380 | */
|
381 | if(i2c_10bit_address_restart != 1)
|
382 | {
|
383 | // extract the information for this message
|
384 | i2c_address = p_i2c1_trb_current->address;
|
385 | pi2c_buf_ptr = p_i2c1_trb_current->pbuffer;
|
386 | i2c_bytes_left = p_i2c1_trb_current->length;
|
387 | }
|
388 |
|
389 | // check for 10-bit address
|
390 | if(!I2C1_7bit && (0x0 != i2c_address))
|
391 | {
|
392 | if (0 == i2c_10bit_address_restart)
|
393 | {
|
394 | // we have a 10 bit address
|
395 | // send bits<9:8>
|
396 | // mask bit 0 as this is always a write
|
397 | I2C1_TRANSMIT_REG = 0xF0 | ((i2c_address >> 8) & 0x0006);
|
398 | i2c1_state = S_MASTER_SEND_ADDR_10BIT_LSB;
|
399 | }
|
400 | else
|
401 | {
|
402 | // resending address bits<9:8> to trigger read
|
403 | I2C1_TRANSMIT_REG = i2c_address;
|
404 | i2c1_state = S_MASTER_ACK_ADDR;
|
405 | // reset the flag so the next access is ok
|
406 | i2c_10bit_address_restart = 0;
|
407 | }
|
408 | }
|
409 | else
|
410 | {
|
411 | // Transmit the address
|
412 | I2C1_TRANSMIT_REG = i2c_address;
|
413 | if(i2c_address & 0x01)
|
414 | {
|
415 | // Next state is to wait for address to be acked
|
416 | i2c1_state = S_MASTER_ACK_ADDR;
|
417 | }
|
418 | else
|
419 | {
|
420 | // Next state is transmit
|
421 | i2c1_state = S_MASTER_SEND_DATA;
|
422 | }
|
423 | }
|
424 | break;
|
425 |
|
426 | case S_MASTER_SEND_DATA:
|
427 |
|
428 | // Make sure the previous byte was acknowledged
|
429 | if(I2C1_ACKNOWLEDGE_STATUS_BIT)
|
430 | {
|
431 | // Transmission was not acknowledged
|
432 | i2c1_object.i2cErrors++;
|
433 |
|
434 | // Reset the Ack flag
|
435 | I2C1_ACKNOWLEDGE_STATUS_BIT = 0;
|
436 |
|
437 | // Send a stop flag and go back to idle
|
438 | I2C1_Stop(I2C1_DATA_NO_ACK);
|
439 |
|
440 | }
|
441 | else
|
442 | {
|
443 | // Did we send them all ?
|
444 | if(i2c_bytes_left-- == 0U)
|
445 | {
|
446 | // yup sent them all!
|
447 |
|
448 | // update the trb pointer
|
449 | p_i2c1_trb_current++;
|
450 |
|
451 | // are we done with this string of requests?
|
452 | if(--i2c1_trb_count == 0)
|
453 | {
|
454 | I2C1_Stop(I2C1_MESSAGE_COMPLETE);
|
455 | }
|
456 | else
|
457 | {
|
458 | // no!, there are more TRB to be sent.
|
459 | //I2C1_START_CONDITION_ENABLE_BIT = 1;
|
460 |
|
461 | // In some cases, the slave may require
|
462 | // a restart instead of a start. So use this one
|
463 | // instead.
|
464 | I2C1_REPEAT_START_CONDITION_ENABLE_BIT = 1;
|
465 |
|
466 | // start the i2c request
|
467 | i2c1_state = S_MASTER_SEND_ADDR;
|
468 |
|
469 | }
|
470 | }
|
471 | else
|
472 | {
|
473 | // Grab the next data to transmit
|
474 | I2C1_TRANSMIT_REG = *pi2c_buf_ptr++;
|
475 | }
|
476 | }
|
477 | break;
|
478 |
|
479 | case S_MASTER_ACK_ADDR:
|
480 |
|
481 | /* Make sure the previous byte was acknowledged */
|
482 | if(I2C1_ACKNOWLEDGE_STATUS_BIT)
|
483 | {
|
484 |
|
485 | // Transmission was not acknowledged
|
486 | i2c1_object.i2cErrors++;
|
487 |
|
488 | // Send a stop flag and go back to idle
|
489 | I2C1_Stop(I2C1_MESSAGE_ADDRESS_NO_ACK);
|
490 |
|
491 | // Reset the Ack flag
|
492 | I2C1_ACKNOWLEDGE_STATUS_BIT = 0;
|
493 | }
|
494 | else
|
495 | {
|
496 | I2C1_RECEIVE_ENABLE_BIT = 1;
|
497 | i2c1_state = S_MASTER_ACK_RCV_DATA;
|
498 | }
|
499 | break;
|
500 |
|
501 | case S_MASTER_RCV_DATA:
|
502 |
|
503 | /* Acknowledge is completed. Time for more data */
|
504 |
|
505 | // Next thing is to ack the data
|
506 | i2c1_state = S_MASTER_ACK_RCV_DATA;
|
507 |
|
508 | // Set up to receive a byte of data
|
509 | I2C1_RECEIVE_ENABLE_BIT = 1;
|
510 |
|
511 | break;
|
512 |
|
513 | case S_MASTER_ACK_RCV_DATA:
|
514 |
|
515 | // Grab the byte of data received and acknowledge it
|
516 | *pi2c_buf_ptr++ = I2C1_RECEIVE_REG;
|
517 |
|
518 | // Check if we received them all?
|
519 | if(--i2c_bytes_left)
|
520 | {
|
521 |
|
522 | /* No, there's more to receive */
|
523 |
|
524 | // No, bit 7 is clear. Data is ok
|
525 | // Set the flag to acknowledge the data
|
526 | I2C1_ACKNOWLEDGE_DATA_BIT = 0;
|
527 |
|
528 | // Wait for the acknowledge to complete, then get more
|
529 | i2c1_state = S_MASTER_RCV_DATA;
|
530 | }
|
531 | else
|
532 | {
|
533 |
|
534 | // Yes, it's the last byte. Don't ack it
|
535 | // Flag that we will nak the data
|
536 | I2C1_ACKNOWLEDGE_DATA_BIT = 1;
|
537 |
|
538 | I2C1_FunctionComplete();
|
539 | }
|
540 |
|
541 | // Initiate the acknowledge
|
542 | I2C1_ACKNOWLEDGE_ENABLE_BIT = 1;
|
543 | break;
|
544 |
|
545 | case S_MASTER_RCV_STOP:
|
546 | case S_MASTER_SEND_STOP:
|
547 |
|
548 | // Send the stop flag
|
549 | I2C1_Stop(I2C1_MESSAGE_COMPLETE);
|
550 | break;
|
551 |
|
552 | default:
|
553 |
|
554 | // This case should not happen, if it does then
|
555 | // terminate the transfer
|
556 | i2c1_object.i2cErrors++;
|
557 | I2C1_Stop(I2C1_LOST_STATE);
|
558 | break;
|
559 |
|
560 | }
|
561 | }
|
562 |
|
563 | void I2C1_FunctionComplete(void)
|
564 | {
|
565 |
|
566 | // update the trb pointer
|
567 | p_i2c1_trb_current++;
|
568 |
|
569 | // are we done with this string of requests?
|
570 | if(--i2c1_trb_count == 0)
|
571 | {
|
572 | i2c1_state = S_MASTER_SEND_STOP;
|
573 | }
|
574 | else
|
575 | {
|
576 | i2c1_state = S_MASTER_RESTART;
|
577 | }
|
578 |
|
579 | }
|
580 |
|
581 | void I2C1_Stop(I2C1_MESSAGE_STATUS completion_code)
|
582 | {
|
583 | // then send a stop
|
584 | I2C1_STOP_CONDITION_ENABLE_BIT = 1;
|
585 |
|
586 | // make sure the flag pointer is not NULL
|
587 | if (p_i2c1_current->pTrFlag != NULL)
|
588 | {
|
589 | // update the flag with the completion code
|
590 | *(p_i2c1_current->pTrFlag) = completion_code;
|
591 | }
|
592 |
|
593 | // Done, back to idle
|
594 | i2c1_state = S_MASTER_IDLE;
|
595 |
|
596 | }
|
597 |
|
598 | void I2C1_MasterWrite(
|
599 | uint8_t *pdata,
|
600 | uint8_t length,
|
601 | uint16_t address,
|
602 | I2C1_MESSAGE_STATUS *pflag)
|
603 | {
|
604 | static I2C1_TRANSACTION_REQUEST_BLOCK trBlock;
|
605 |
|
606 | // check if there is space in the queue
|
607 | if (i2c1_object.trStatus.s.full != true)
|
608 | {
|
609 | I2C1_MasterWriteTRBBuild(&trBlock, pdata, length, address);
|
610 | I2C1_MasterTRBInsert(1, &trBlock, pflag);
|
611 | }
|
612 | else
|
613 | {
|
614 | *pflag = I2C1_MESSAGE_FAIL;
|
615 | }
|
616 |
|
617 | }
|
618 |
|
619 | void I2C1_MasterRead(
|
620 | uint8_t *pdata,
|
621 | uint8_t length,
|
622 | uint16_t address,
|
623 | I2C1_MESSAGE_STATUS *pflag)
|
624 | {
|
625 | static I2C1_TRANSACTION_REQUEST_BLOCK trBlock;
|
626 |
|
627 |
|
628 | // check if there is space in the queue
|
629 | if (i2c1_object.trStatus.s.full != true)
|
630 | {
|
631 | I2C1_MasterReadTRBBuild(&trBlock, pdata, length, address);
|
632 | I2C1_MasterTRBInsert(1, &trBlock, pflag);
|
633 | }
|
634 | else
|
635 | {
|
636 | *pflag = I2C1_MESSAGE_FAIL;
|
637 | }
|
638 |
|
639 | }
|
640 |
|
641 | void I2C1_MasterTRBInsert(
|
642 | uint8_t count,
|
643 | I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list,
|
644 | I2C1_MESSAGE_STATUS *pflag)
|
645 | {
|
646 |
|
647 | // check if there is space in the queue
|
648 | if (i2c1_object.trStatus.s.full != true)
|
649 | {
|
650 | *pflag = I2C1_MESSAGE_PENDING;
|
651 |
|
652 | i2c1_object.pTrTail->ptrb_list = ptrb_list;
|
653 | i2c1_object.pTrTail->count = count;
|
654 | i2c1_object.pTrTail->pTrFlag = pflag;
|
655 | i2c1_object.pTrTail++;
|
656 |
|
657 | // check if the end of the array is reached
|
658 | if (i2c1_object.pTrTail == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
|
659 | {
|
660 | // adjust to restart at the beginning of the array
|
661 | i2c1_object.pTrTail = i2c1_tr_queue;
|
662 | }
|
663 |
|
664 | // since we added one item to be processed, we know
|
665 | // it is not empty, so set the empty status to false
|
666 | i2c1_object.trStatus.s.empty = false;
|
667 |
|
668 | // check if full
|
669 | if (i2c1_object.pTrHead == i2c1_object.pTrTail)
|
670 | {
|
671 | // it is full, set the full status to true
|
672 | i2c1_object.trStatus.s.full = true;
|
673 | }
|
674 |
|
675 | }
|
676 | else
|
677 | {
|
678 | *pflag = I2C1_MESSAGE_FAIL;
|
679 | }
|
680 |
|
681 | // for interrupt based
|
682 | if (*pflag == I2C1_MESSAGE_PENDING)
|
683 | {
|
684 | while(i2c1_state != S_MASTER_IDLE);
|
685 | {
|
686 | // force the task to run since we know that the queue has
|
687 | // something that needs to be sent
|
688 | PIR3bits.SSP1IF = true;
|
689 | }
|
690 | } // block until request is complete
|
691 |
|
692 | }
|
693 |
|
694 | void I2C1_MasterReadTRBBuild(
|
695 | I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
|
696 | uint8_t *pdata,
|
697 | uint8_t length,
|
698 | uint16_t address)
|
699 | {
|
700 | ptrb->address = address << 1;
|
701 | // make this a read
|
702 | ptrb->address |= 0x01;
|
703 | ptrb->length = length;
|
704 | ptrb->pbuffer = pdata;
|
705 | }
|
706 |
|
707 | void I2C1_MasterWriteTRBBuild(
|
708 | I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
|
709 | uint8_t *pdata,
|
710 | uint8_t length,
|
711 | uint16_t address)
|
712 | {
|
713 | ptrb->address = address << 1;
|
714 | ptrb->length = length;
|
715 | ptrb->pbuffer = pdata;
|
716 | }
|
717 |
|
718 | bool I2C1_MasterQueueIsEmpty(void)
|
719 | {
|
720 | return(i2c1_object.trStatus.s.empty);
|
721 | }
|
722 |
|
723 | bool I2C1_MasterQueueIsFull(void)
|
724 | {
|
725 | return(i2c1_object.trStatus.s.full);
|
726 | }
|
727 |
|
728 | void I2C1_BusCollisionISR( void )
|
729 | {
|
730 | // enter bus collision handling code here
|
731 | }
|
732 |
|
733 |
|
734 | /**
|
735 | End of File
|
736 | */
|