2 FreeRTOS V7.5.3 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
28 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
29 >>! the source code for proprietary components outside of the FreeRTOS
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
67 /* Standard includes. */
\r
70 /* Scheduler include files. */
\r
71 #include "FreeRTOS.h"
\r
76 /* Application includes. */
\r
79 /*-----------------------------------------------------------*/
\r
81 /* Bit definitions within the I2CONCLR register. */
\r
82 #define i2cSTA_BIT ( ( unsigned char ) 0x20 )
\r
83 #define i2cSI_BIT ( ( unsigned char ) 0x08 )
\r
84 #define i2cSTO_BIT ( ( unsigned char ) 0x10 )
\r
85 #define i2cAA_BIT ( ( unsigned char ) 0x04 )
\r
87 /* Status codes for the I2STAT register. */
\r
88 #define i2cSTATUS_START_TXED ( 0x08 )
\r
89 #define i2cSTATUS_REP_START_TXED ( 0x10 )
\r
90 #define i2cSTATUS_TX_ADDR_ACKED ( 0x18 )
\r
91 #define i2cSTATUS_DATA_TXED ( 0x28 )
\r
92 #define i2cSTATUS_RX_ADDR_ACKED ( 0x40 )
\r
93 #define i2cSTATUS_DATA_RXED ( 0x50 )
\r
94 #define i2cSTATUS_LAST_BYTE_RXED ( 0x58 )
\r
96 /* Constants for operation of the VIC. */
\r
97 #define i2cCLEAR_VIC_INTERRUPT ( 0 )
\r
99 /* Misc constants. */
\r
100 #define i2cJUST_ONE_BYTE_TO_RX ( 1 )
\r
101 #define i2cBUFFER_ADDRESS_BYTES ( 2 )
\r
103 /* End the current transmission and free the bus. */
\r
104 #define i2cEND_TRANSMISSION( lStatus ) \
\r
106 I2C_I2CONCLR = i2cAA_BIT; \
\r
107 I2C_I2CONSET = i2cSTO_BIT; \
\r
108 eCurrentState = eSentStart; \
\r
109 lTransactionCompleted = lStatus; \
\r
111 /*-----------------------------------------------------------*/
\r
113 /* Valid i2c communication states. */
\r
116 eSentStart, /*<< Last action was the transmission of a start bit. */
\r
117 eSentAddressForWrite, /*<< Last action was the transmission of the slave address we are to write to. */
\r
118 eSentAddressForRead, /*<< Last action was the transmission of the slave address we are to read from. */
\r
119 eSentData, /*<< Last action was the transmission of a data byte. */
\r
120 eReceiveData /*<< We expected data to be received. */
\r
122 /*-----------------------------------------------------------*/
\r
124 /* Points to the message currently being sent. */
\r
125 volatile xI2CMessage *pxCurrentMessage = NULL;
\r
127 /* The queue of messages waiting to be transmitted. */
\r
128 static xQueueHandle xMessagesForTx;
\r
130 /* Flag used to indicate whether or not the ISR is amid sending a message. */
\r
131 unsigned long ulBusFree = ( unsigned long ) pdTRUE;
\r
133 /* Setting this to true will cause the TCP task to think a message is
\r
134 complete and thus restart. It can therefore be used under error states
\r
135 to force a restart. */
\r
136 volatile long lTransactionCompleted = pdTRUE;
\r
138 /*-----------------------------------------------------------*/
\r
140 void vI2CISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxTxMessages, unsigned long **ppulBusFree )
\r
142 /* Create the queues used to hold Rx and Tx characters. */
\r
143 xMessagesForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( xI2CMessage * ) );
\r
145 /* Pass back a reference to the queue and bus free flag so the I2C API file
\r
146 can post messages. */
\r
147 *pxTxMessages = xMessagesForTx;
\r
148 *ppulBusFree = &ulBusFree;
\r
150 /*-----------------------------------------------------------*/
\r
152 /* The ISR entry point. */
\r
153 void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));
\r
155 /* The ISR function to perform the actual work. This must be a separate
\r
156 function from the wrapper to ensure the correct stack frame is set up. */
\r
157 void vI2C_ISR_Handler( void );
\r
159 /*-----------------------------------------------------------*/
\r
161 void vI2C_ISR_Wrapper( void )
\r
163 /* Save the context of the interrupted task. */
\r
164 portSAVE_CONTEXT();
\r
166 /* Call the handler to perform the actual work. This must be a
\r
167 separate function to ensure the correct stack frame is set up. */
\r
168 vI2C_ISR_Handler();
\r
170 /* Restore the context of whichever task is going to run next. */
\r
171 portRESTORE_CONTEXT();
\r
173 /*-----------------------------------------------------------*/
\r
175 void vI2C_ISR_Handler( void )
\r
177 /* Holds the current transmission state. */
\r
178 static I2C_STATE eCurrentState = eSentStart;
\r
179 static long lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */
\r
180 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
183 /* The action taken for this interrupt depends on our current state. */
\r
184 switch( eCurrentState )
\r
188 /* We sent a start bit, if it was successful we can
\r
189 go on to send the slave address. */
\r
190 if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )
\r
192 /* Send the slave address. */
\r
193 I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;
\r
195 if( pxCurrentMessage->ucSlaveAddress & i2cREAD )
\r
197 /* We are then going to read bytes back from the
\r
199 eCurrentState = eSentAddressForRead;
\r
201 /* Initialise the buffer index so the first byte goes
\r
202 into the first buffer position. */
\r
207 /* We are then going to write some data to the slave. */
\r
208 eCurrentState = eSentAddressForWrite;
\r
210 /* When writing bytes we first have to send the two
\r
211 byte buffer address so lMessageIndex is set negative,
\r
212 when it reaches 0 it is time to send the actual data. */
\r
213 lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;
\r
218 /* Could not send the start bit so give up. */
\r
219 i2cEND_TRANSMISSION( pdFAIL );
\r
222 I2C_I2CONCLR = i2cSTA_BIT;
\r
226 case eSentAddressForWrite :
\r
228 /* We sent the address of the slave we are going to write to.
\r
229 If this was acknowledged we can go on to send the data. */
\r
230 if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )
\r
232 /* Start the first byte transmitting which is the
\r
233 first byte of the buffer address to which the data will
\r
235 I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;
\r
236 eCurrentState = eSentData;
\r
240 /* Address was not acknowledged so give up. */
\r
241 i2cEND_TRANSMISSION( pdFAIL );
\r
245 case eSentAddressForRead :
\r
247 /* We sent the address of the slave we are going to read from.
\r
248 If this was acknowledged we can go on to read the data. */
\r
249 if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )
\r
251 eCurrentState = eReceiveData;
\r
252 if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )
\r
254 /* Don't ack the last byte of the message. */
\r
255 I2C_I2CONSET = i2cAA_BIT;
\r
260 /* Something unexpected happened - give up. */
\r
261 i2cEND_TRANSMISSION( pdFAIL );
\r
265 case eReceiveData :
\r
267 /* We have just received a byte from the slave. */
\r
268 if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )
\r
270 /* Buffer the byte just received then increment the index
\r
271 so it points to the next free space. */
\r
272 pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;
\r
275 /* How many more bytes are we expecting to receive? */
\r
276 lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;
\r
277 if( lBytesLeft == ( unsigned long ) 0 )
\r
279 /* This was the last byte in the message. */
\r
280 i2cEND_TRANSMISSION( pdPASS );
\r
282 /* If xMessageCompleteSemaphore is not null then there
\r
283 is a task waiting for this message to complete and we
\r
284 must 'give' the semaphore so the task is woken.*/
\r
285 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
287 xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
\r
290 /* Are there any other messages to transact? */
\r
291 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
293 /* Start the next message - which was
\r
294 retrieved from the queue. */
\r
295 I2C_I2CONSET = i2cSTA_BIT;
\r
299 /* No more messages were found to be waiting for
\r
300 transaction so the bus is free. */
\r
301 ulBusFree = ( unsigned long ) pdTRUE;
\r
306 /* There are more bytes to receive but don't ack the
\r
308 if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )
\r
310 I2C_I2CONCLR = i2cAA_BIT;
\r
316 /* Something unexpected happened - give up. */
\r
317 i2cEND_TRANSMISSION( pdFAIL );
\r
324 /* We sent a data byte, if successful send the next byte in
\r
326 if( I2C_I2STAT == i2cSTATUS_DATA_TXED )
\r
328 /* Index to the next byte to send. */
\r
330 if( lMessageIndex < 0 )
\r
332 /* lMessage index is still negative so we have so far
\r
333 only sent the first byte of the buffer address. Send
\r
334 the second byte now, then initialise the buffer index
\r
335 to zero so the next byte sent comes from the actual
\r
337 I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;
\r
339 else if( lMessageIndex < pxCurrentMessage->lMessageLength )
\r
341 /* Simply send the next byte in the tx buffer. */
\r
342 I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];
\r
346 /* No more bytes in this message to be send. Finished
\r
347 sending message - send a stop bit. */
\r
348 i2cEND_TRANSMISSION( pdPASS );
\r
350 /* If xMessageCompleteSemaphore is not null then there
\r
351 is a task waiting for this message to be sent and the
\r
352 semaphore must be 'given' to wake the task. */
\r
353 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
355 xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
\r
358 /* Are there any other messages to transact? */
\r
359 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
361 /* Start the next message from the Tx queue. */
\r
362 I2C_I2CONSET = i2cSTA_BIT;
\r
366 /* No more message were queues for transaction so
\r
367 the bus is free. */
\r
368 ulBusFree = ( unsigned long ) pdTRUE;
\r
374 /* Something unexpected happened, give up. */
\r
375 i2cEND_TRANSMISSION( pdFAIL );
\r
381 /* Should never get here. */
\r
382 eCurrentState = eSentStart;
\r
386 /* Clear the interrupt. */
\r
387 I2C_I2CONCLR = i2cSI_BIT;
\r
388 VICVectAddr = i2cCLEAR_VIC_INTERRUPT;
\r
390 if( xHigherPriorityTaskWoken )
\r
392 portYIELD_FROM_ISR();
\r
395 /*-----------------------------------------------------------*/
\r