2 FreeRTOS V6.1.0 - Copyright (C) 2010 Real Time Engineers Ltd.
\r
4 ***************************************************************************
\r
8 * + New to FreeRTOS, *
\r
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
\r
10 * + Looking for basic training, *
\r
11 * + Wanting to improve your FreeRTOS skills and productivity *
\r
13 * then take a look at the FreeRTOS books - available as PDF or paperback *
\r
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
\r
16 * http://www.FreeRTOS.org/Documentation *
\r
18 * A pdf reference manual is also available. Both are usually delivered *
\r
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
\r
20 * and 8pm GMT (although please allow up to 24 hours in case of *
\r
21 * exceptional circumstances). Thank you for your support! *
\r
23 ***************************************************************************
\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 exception to the GPL is included to allow you to distribute
\r
31 a combined work that includes FreeRTOS without being obliged to provide the
\r
32 source code for proprietary components outside of the FreeRTOS kernel.
\r
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
35 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 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
55 /* Standard includes. */
\r
58 /* Scheduler include files. */
\r
59 #include "FreeRTOS.h"
\r
64 /* Application includes. */
\r
67 /*-----------------------------------------------------------*/
\r
69 /* Bit definitions within the I2CONCLR register. */
\r
70 #define i2cSTA_BIT ( ( unsigned char ) 0x20 )
\r
71 #define i2cSI_BIT ( ( unsigned char ) 0x08 )
\r
72 #define i2cSTO_BIT ( ( unsigned char ) 0x10 )
\r
73 #define i2cAA_BIT ( ( unsigned char ) 0x04 )
\r
75 /* Status codes for the I2STAT register. */
\r
76 #define i2cSTATUS_START_TXED ( 0x08 )
\r
77 #define i2cSTATUS_REP_START_TXED ( 0x10 )
\r
78 #define i2cSTATUS_TX_ADDR_ACKED ( 0x18 )
\r
79 #define i2cSTATUS_DATA_TXED ( 0x28 )
\r
80 #define i2cSTATUS_RX_ADDR_ACKED ( 0x40 )
\r
81 #define i2cSTATUS_DATA_RXED ( 0x50 )
\r
82 #define i2cSTATUS_LAST_BYTE_RXED ( 0x58 )
\r
84 /* Constants for operation of the VIC. */
\r
85 #define i2cCLEAR_VIC_INTERRUPT ( 0 )
\r
87 /* Misc constants. */
\r
88 #define i2cJUST_ONE_BYTE_TO_RX ( 1 )
\r
89 #define i2cBUFFER_ADDRESS_BYTES ( 2 )
\r
91 /* End the current transmission and free the bus. */
\r
92 #define i2cEND_TRANSMISSION( lStatus ) \
\r
94 I2C_I2CONCLR = i2cAA_BIT; \
\r
95 I2C_I2CONSET = i2cSTO_BIT; \
\r
96 eCurrentState = eSentStart; \
\r
97 lTransactionCompleted = lStatus; \
\r
99 /*-----------------------------------------------------------*/
\r
101 /* Valid i2c communication states. */
\r
104 eSentStart, /*<< Last action was the transmission of a start bit. */
\r
105 eSentAddressForWrite, /*<< Last action was the transmission of the slave address we are to write to. */
\r
106 eSentAddressForRead, /*<< Last action was the transmission of the slave address we are to read from. */
\r
107 eSentData, /*<< Last action was the transmission of a data byte. */
\r
108 eReceiveData /*<< We expected data to be received. */
\r
110 /*-----------------------------------------------------------*/
\r
112 /* Points to the message currently being sent. */
\r
113 volatile xI2CMessage *pxCurrentMessage = NULL;
\r
115 /* The queue of messages waiting to be transmitted. */
\r
116 static xQueueHandle xMessagesForTx;
\r
118 /* Flag used to indicate whether or not the ISR is amid sending a message. */
\r
119 unsigned long ulBusFree = ( unsigned long ) pdTRUE;
\r
121 /* Setting this to true will cause the TCP task to think a message is
\r
122 complete and thus restart. It can therefore be used under error states
\r
123 to force a restart. */
\r
124 volatile long lTransactionCompleted = pdTRUE;
\r
126 /*-----------------------------------------------------------*/
\r
128 void vI2CISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxTxMessages, unsigned long **ppulBusFree )
\r
130 /* Create the queues used to hold Rx and Tx characters. */
\r
131 xMessagesForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( xI2CMessage * ) );
\r
133 /* Pass back a reference to the queue and bus free flag so the I2C API file
\r
134 can post messages. */
\r
135 *pxTxMessages = xMessagesForTx;
\r
136 *ppulBusFree = &ulBusFree;
\r
138 /*-----------------------------------------------------------*/
\r
140 /* The ISR entry point. */
\r
141 void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));
\r
143 /* The ISR function to perform the actual work. This must be a separate
\r
144 function from the wrapper to ensure the correct stack frame is set up. */
\r
145 void vI2C_ISR_Handler( void );
\r
147 /*-----------------------------------------------------------*/
\r
149 void vI2C_ISR_Wrapper( void )
\r
151 /* Save the context of the interrupted task. */
\r
152 portSAVE_CONTEXT();
\r
154 /* Call the handler to perform the actual work. This must be a
\r
155 separate function to ensure the correct stack frame is set up. */
\r
156 vI2C_ISR_Handler();
\r
158 /* Restore the context of whichever task is going to run next. */
\r
159 portRESTORE_CONTEXT();
\r
161 /*-----------------------------------------------------------*/
\r
163 void vI2C_ISR_Handler( void )
\r
165 /* Holds the current transmission state. */
\r
166 static I2C_STATE eCurrentState = eSentStart;
\r
167 static long lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */
\r
168 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
171 /* The action taken for this interrupt depends on our current state. */
\r
172 switch( eCurrentState )
\r
176 /* We sent a start bit, if it was successful we can
\r
177 go on to send the slave address. */
\r
178 if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )
\r
180 /* Send the slave address. */
\r
181 I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;
\r
183 if( pxCurrentMessage->ucSlaveAddress & i2cREAD )
\r
185 /* We are then going to read bytes back from the
\r
187 eCurrentState = eSentAddressForRead;
\r
189 /* Initialise the buffer index so the first byte goes
\r
190 into the first buffer position. */
\r
195 /* We are then going to write some data to the slave. */
\r
196 eCurrentState = eSentAddressForWrite;
\r
198 /* When writing bytes we first have to send the two
\r
199 byte buffer address so lMessageIndex is set negative,
\r
200 when it reaches 0 it is time to send the actual data. */
\r
201 lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;
\r
206 /* Could not send the start bit so give up. */
\r
207 i2cEND_TRANSMISSION( pdFAIL );
\r
210 I2C_I2CONCLR = i2cSTA_BIT;
\r
214 case eSentAddressForWrite :
\r
216 /* We sent the address of the slave we are going to write to.
\r
217 If this was acknowledged we can go on to send the data. */
\r
218 if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )
\r
220 /* Start the first byte transmitting which is the
\r
221 first byte of the buffer address to which the data will
\r
223 I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;
\r
224 eCurrentState = eSentData;
\r
228 /* Address was not acknowledged so give up. */
\r
229 i2cEND_TRANSMISSION( pdFAIL );
\r
233 case eSentAddressForRead :
\r
235 /* We sent the address of the slave we are going to read from.
\r
236 If this was acknowledged we can go on to read the data. */
\r
237 if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )
\r
239 eCurrentState = eReceiveData;
\r
240 if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )
\r
242 /* Don't ack the last byte of the message. */
\r
243 I2C_I2CONSET = i2cAA_BIT;
\r
248 /* Something unexpected happened - give up. */
\r
249 i2cEND_TRANSMISSION( pdFAIL );
\r
253 case eReceiveData :
\r
255 /* We have just received a byte from the slave. */
\r
256 if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )
\r
258 /* Buffer the byte just received then increment the index
\r
259 so it points to the next free space. */
\r
260 pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;
\r
263 /* How many more bytes are we expecting to receive? */
\r
264 lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;
\r
265 if( lBytesLeft == ( unsigned long ) 0 )
\r
267 /* This was the last byte in the message. */
\r
268 i2cEND_TRANSMISSION( pdPASS );
\r
270 /* If xMessageCompleteSemaphore is not null then there
\r
271 is a task waiting for this message to complete and we
\r
272 must 'give' the semaphore so the task is woken.*/
\r
273 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
275 xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
\r
278 /* Are there any other messages to transact? */
\r
279 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
281 /* Start the next message - which was
\r
282 retrieved from the queue. */
\r
283 I2C_I2CONSET = i2cSTA_BIT;
\r
287 /* No more messages were found to be waiting for
\r
288 transaction so the bus is free. */
\r
289 ulBusFree = ( unsigned long ) pdTRUE;
\r
294 /* There are more bytes to receive but don't ack the
\r
296 if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )
\r
298 I2C_I2CONCLR = i2cAA_BIT;
\r
304 /* Something unexpected happened - give up. */
\r
305 i2cEND_TRANSMISSION( pdFAIL );
\r
312 /* We sent a data byte, if successful send the next byte in
\r
314 if( I2C_I2STAT == i2cSTATUS_DATA_TXED )
\r
316 /* Index to the next byte to send. */
\r
318 if( lMessageIndex < 0 )
\r
320 /* lMessage index is still negative so we have so far
\r
321 only sent the first byte of the buffer address. Send
\r
322 the second byte now, then initialise the buffer index
\r
323 to zero so the next byte sent comes from the actual
\r
325 I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;
\r
327 else if( lMessageIndex < pxCurrentMessage->lMessageLength )
\r
329 /* Simply send the next byte in the tx buffer. */
\r
330 I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];
\r
334 /* No more bytes in this message to be send. Finished
\r
335 sending message - send a stop bit. */
\r
336 i2cEND_TRANSMISSION( pdPASS );
\r
338 /* If xMessageCompleteSemaphore is not null then there
\r
339 is a task waiting for this message to be sent and the
\r
340 semaphore must be 'given' to wake the task. */
\r
341 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
343 xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
\r
346 /* Are there any other messages to transact? */
\r
347 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
\r
349 /* Start the next message from the Tx queue. */
\r
350 I2C_I2CONSET = i2cSTA_BIT;
\r
354 /* No more message were queues for transaction so
\r
355 the bus is free. */
\r
356 ulBusFree = ( unsigned long ) pdTRUE;
\r
362 /* Something unexpected happened, give up. */
\r
363 i2cEND_TRANSMISSION( pdFAIL );
\r
369 /* Should never get here. */
\r
370 eCurrentState = eSentStart;
\r
374 /* Clear the interrupt. */
\r
375 I2C_I2CONCLR = i2cSI_BIT;
\r
376 VICVectAddr = i2cCLEAR_VIC_INTERRUPT;
\r
378 if( xHigherPriorityTaskWoken )
\r
380 portYIELD_FROM_ISR();
\r
383 /*-----------------------------------------------------------*/
\r