2 FreeRTOS V7.1.1 - Copyright (C) 2012 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 ***************************************************************************
\r
46 * Having a problem? Start by reading the FAQ "My application does *
\r
47 * not run, what could be wrong? *
\r
49 * http://www.FreeRTOS.org/FAQHelp.html *
\r
51 ***************************************************************************
\r
54 http://www.FreeRTOS.org - Documentation, training, latest information,
\r
55 license and contact details.
\r
57 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
58 including FreeRTOS+Trace - an indispensable productivity tool.
\r
60 Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell
\r
61 the code with commercial support, indemnification, and middleware, under
\r
62 the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also
\r
63 provide a safety engineered and independently SIL3 certified version under
\r
64 the SafeRTOS brand: http://www.SafeRTOS.com.
\r
68 /* Standard includes. */
\r
71 /* Scheduler include files. */
\r
72 #include "FreeRTOS.h"
\r
77 /* Application includes. */
\r
80 /*-----------------------------------------------------------*/
\r
82 /* Bit definitions within the I2CONCLR register. */
\r
83 #define i2cSTA_BIT ( ( unsigned char ) 0x20 )
\r
84 #define i2cSI_BIT ( ( unsigned char ) 0x08 )
\r
85 #define i2cSTO_BIT ( ( unsigned char ) 0x10 )
\r
86 #define i2cAA_BIT ( ( unsigned char ) 0x04 )
\r
88 /* Status codes for the I2STAT register. */
\r
89 #define i2cSTATUS_START_TXED ( 0x08 )
\r
90 #define i2cSTATUS_REP_START_TXED ( 0x10 )
\r
91 #define i2cSTATUS_TX_ADDR_ACKED ( 0x18 )
\r
92 #define i2cSTATUS_DATA_TXED ( 0x28 )
\r
93 #define i2cSTATUS_RX_ADDR_ACKED ( 0x40 )
\r
94 #define i2cSTATUS_DATA_RXED ( 0x50 )
\r
95 #define i2cSTATUS_LAST_BYTE_RXED ( 0x58 )
\r
97 /* Constants for operation of the VIC. */
\r
98 #define i2cCLEAR_VIC_INTERRUPT ( 0 )
\r
100 /* Misc constants. */
\r
101 #define i2cJUST_ONE_BYTE_TO_RX ( 1 )
\r
102 #define i2cBUFFER_ADDRESS_BYTES ( 2 )
\r
104 /* End the current transmission and free the bus. */
\r
105 #define i2cEND_TRANSMISSION( lStatus ) \
\r
107 I2C_I2CONCLR = i2cAA_BIT; \
\r
108 I2C_I2CONSET = i2cSTO_BIT; \
\r
109 eCurrentState = eSentStart; \
\r
110 lTransactionCompleted = lStatus; \
\r
112 /*-----------------------------------------------------------*/
\r
114 /* Valid i2c communication states. */
\r
117 eSentStart, /*<< Last action was the transmission of a start bit. */
\r
118 eSentAddressForWrite, /*<< Last action was the transmission of the slave address we are to write to. */
\r
119 eSentAddressForRead, /*<< Last action was the transmission of the slave address we are to read from. */
\r
120 eSentData, /*<< Last action was the transmission of a data byte. */
\r
121 eReceiveData /*<< We expected data to be received. */
\r
123 /*-----------------------------------------------------------*/
\r
125 /* Points to the message currently being sent. */
\r
126 volatile xI2CMessage *pxCurrentMessage = NULL;
\r
128 /* The queue of messages waiting to be transmitted. */
\r
129 static xQueueHandle xMessagesForTx;
\r
131 /* Flag used to indicate whether or not the ISR is amid sending a message. */
\r
132 unsigned long ulBusFree = ( unsigned long ) pdTRUE;
\r
134 /* Setting this to true will cause the TCP task to think a message is
\r
135 complete and thus restart. It can therefore be used under error states
\r
136 to force a restart. */
\r
137 volatile long lTransactionCompleted = pdTRUE;
\r
139 /*-----------------------------------------------------------*/
\r
141 void vI2CISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxTxMessages, unsigned long **ppulBusFree )
\r
143 /* Create the queues used to hold Rx and Tx characters. */
\r
144 xMessagesForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( xI2CMessage * ) );
\r
146 /* Pass back a reference to the queue and bus free flag so the I2C API file
\r
147 can post messages. */
\r
148 *pxTxMessages = xMessagesForTx;
\r
149 *ppulBusFree = &ulBusFree;
\r
151 /*-----------------------------------------------------------*/
\r
153 /* The ISR entry point. */
\r
154 void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));
\r
156 /* The ISR function to perform the actual work. This must be a separate
\r
157 function from the wrapper to ensure the correct stack frame is set up. */
\r
158 void vI2C_ISR_Handler( void );
\r
160 /*-----------------------------------------------------------*/
\r
162 void vI2C_ISR_Wrapper( void )
\r
164 /* Save the context of the interrupted task. */
\r
165 portSAVE_CONTEXT();
\r
167 /* Call the handler to perform the actual work. This must be a
\r
168 separate function to ensure the correct stack frame is set up. */
\r
169 vI2C_ISR_Handler();
\r
171 /* Restore the context of whichever task is going to run next. */
\r
172 portRESTORE_CONTEXT();
\r
174 /*-----------------------------------------------------------*/
\r
176 void vI2C_ISR_Handler( void )
\r
178 /* Holds the current transmission state. */
\r
179 static I2C_STATE eCurrentState = eSentStart;
\r
180 static long lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */
\r
181 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
184 /* The action taken for this interrupt depends on our current state. */
\r
185 switch( eCurrentState )
\r
189 /* We sent a start bit, if it was successful we can
\r
190 go on to send the slave address. */
\r
191 if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )
\r
193 /* Send the slave address. */
\r
194 I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;
\r
196 if( pxCurrentMessage->ucSlaveAddress & i2cREAD )
\r
198 /* We are then going to read bytes back from the
\r
200 eCurrentState = eSentAddressForRead;
\r
202 /* Initialise the buffer index so the first byte goes
\r
203 into the first buffer position. */
\r
208 /* We are then going to write some data to the slave. */
\r
209 eCurrentState = eSentAddressForWrite;
\r
211 /* When writing bytes we first have to send the two
\r
212 byte buffer address so lMessageIndex is set negative,
\r
213 when it reaches 0 it is time to send the actual data. */
\r
214 lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;
\r
219 /* Could not send the start bit so give up. */
\r
220 i2cEND_TRANSMISSION( pdFAIL );
\r
223 I2C_I2CONCLR = i2cSTA_BIT;
\r
227 case eSentAddressForWrite :
\r
229 /* We sent the address of the slave we are going to write to.
\r
230 If this was acknowledged we can go on to send the data. */
\r
231 if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )
\r
233 /* Start the first byte transmitting which is the
\r
234 first byte of the buffer address to which the data will
\r
236 I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;
\r
237 eCurrentState = eSentData;
\r
241 /* Address was not acknowledged so give up. */
\r
242 i2cEND_TRANSMISSION( pdFAIL );
\r
246 case eSentAddressForRead :
\r
248 /* We sent the address of the slave we are going to read from.
\r
249 If this was acknowledged we can go on to read the data. */
\r
250 if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )
\r
252 eCurrentState = eReceiveData;
\r
253 if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )
\r
255 /* Don't ack the last byte of the message. */
\r
256 I2C_I2CONSET = i2cAA_BIT;
\r
261 /* Something unexpected happened - give up. */
\r
262 i2cEND_TRANSMISSION( pdFAIL );
\r
266 case eReceiveData :
\r
268 /* We have just received a byte from the slave. */
\r
269 if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )
\r
271 /* Buffer the byte just received then increment the index
\r
272 so it points to the next free space. */
\r
273 pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;
\r
276 /* How many more bytes are we expecting to receive? */
\r
277 lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;
\r
278 if( lBytesLeft == ( unsigned long ) 0 )
\r
280 /* This was the last byte in the message. */
\r
281 i2cEND_TRANSMISSION( pdPASS );
\r
283 /* If xMessageCompleteSemaphore is not null then there
\r
284 is a task waiting for this message to complete and we
\r
285 must 'give' the semaphore so the task is woken.*/
\r
286 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
288 xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
\r
291 /* Are there any other messages to transact? */
\r
292 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
294 /* Start the next message - which was
\r
295 retrieved from the queue. */
\r
296 I2C_I2CONSET = i2cSTA_BIT;
\r
300 /* No more messages were found to be waiting for
\r
301 transaction so the bus is free. */
\r
302 ulBusFree = ( unsigned long ) pdTRUE;
\r
307 /* There are more bytes to receive but don't ack the
\r
309 if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )
\r
311 I2C_I2CONCLR = i2cAA_BIT;
\r
317 /* Something unexpected happened - give up. */
\r
318 i2cEND_TRANSMISSION( pdFAIL );
\r
325 /* We sent a data byte, if successful send the next byte in
\r
327 if( I2C_I2STAT == i2cSTATUS_DATA_TXED )
\r
329 /* Index to the next byte to send. */
\r
331 if( lMessageIndex < 0 )
\r
333 /* lMessage index is still negative so we have so far
\r
334 only sent the first byte of the buffer address. Send
\r
335 the second byte now, then initialise the buffer index
\r
336 to zero so the next byte sent comes from the actual
\r
338 I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;
\r
340 else if( lMessageIndex < pxCurrentMessage->lMessageLength )
\r
342 /* Simply send the next byte in the tx buffer. */
\r
343 I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];
\r
347 /* No more bytes in this message to be send. Finished
\r
348 sending message - send a stop bit. */
\r
349 i2cEND_TRANSMISSION( pdPASS );
\r
351 /* If xMessageCompleteSemaphore is not null then there
\r
352 is a task waiting for this message to be sent and the
\r
353 semaphore must be 'given' to wake the task. */
\r
354 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
356 xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
\r
359 /* Are there any other messages to transact? */
\r
360 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
362 /* Start the next message from the Tx queue. */
\r
363 I2C_I2CONSET = i2cSTA_BIT;
\r
367 /* No more message were queues for transaction so
\r
368 the bus is free. */
\r
369 ulBusFree = ( unsigned long ) pdTRUE;
\r
375 /* Something unexpected happened, give up. */
\r
376 i2cEND_TRANSMISSION( pdFAIL );
\r
382 /* Should never get here. */
\r
383 eCurrentState = eSentStart;
\r
387 /* Clear the interrupt. */
\r
388 I2C_I2CONCLR = i2cSI_BIT;
\r
389 VICVectAddr = i2cCLEAR_VIC_INTERRUPT;
\r
391 if( xHigherPriorityTaskWoken )
\r
393 portYIELD_FROM_ISR();
\r
396 /*-----------------------------------------------------------*/
\r