2 FreeRTOS.org V4.6.0 - Copyright (C) 2003-2007 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
31 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
\r
32 with commercial development and support options.
\r
33 ***************************************************************************
\r
37 /* Standard includes. */
\r
40 /* Scheduler include files. */
\r
41 #include "FreeRTOS.h"
\r
46 /* Application includes. */
\r
49 /*-----------------------------------------------------------*/
\r
51 /* Bit definitions within the I2CONCLR register. */
\r
52 #define i2cSTA_BIT ( ( unsigned portCHAR ) 0x20 )
\r
53 #define i2cSI_BIT ( ( unsigned portCHAR ) 0x08 )
\r
54 #define i2cSTO_BIT ( ( unsigned portCHAR ) 0x10 )
\r
55 #define i2cAA_BIT ( ( unsigned portCHAR ) 0x04 )
\r
57 /* Status codes for the I2STAT register. */
\r
58 #define i2cSTATUS_START_TXED ( 0x08 )
\r
59 #define i2cSTATUS_REP_START_TXED ( 0x10 )
\r
60 #define i2cSTATUS_TX_ADDR_ACKED ( 0x18 )
\r
61 #define i2cSTATUS_DATA_TXED ( 0x28 )
\r
62 #define i2cSTATUS_RX_ADDR_ACKED ( 0x40 )
\r
63 #define i2cSTATUS_DATA_RXED ( 0x50 )
\r
64 #define i2cSTATUS_LAST_BYTE_RXED ( 0x58 )
\r
66 /* Constants for operation of the VIC. */
\r
67 #define i2cCLEAR_VIC_INTERRUPT ( 0 )
\r
69 /* Misc constants. */
\r
70 #define i2cJUST_ONE_BYTE_TO_RX ( 1 )
\r
71 #define i2cBUFFER_ADDRESS_BYTES ( 2 )
\r
73 /* End the current transmission and free the bus. */
\r
74 #define i2cEND_TRANSMISSION( lStatus ) \
\r
76 I2C_I2CONCLR = i2cAA_BIT; \
\r
77 I2C_I2CONSET = i2cSTO_BIT; \
\r
78 eCurrentState = eSentStart; \
\r
79 lTransactionCompleted = lStatus; \
\r
81 /*-----------------------------------------------------------*/
\r
83 /* Valid i2c communication states. */
\r
86 eSentStart, /*<< Last action was the transmission of a start bit. */
\r
87 eSentAddressForWrite, /*<< Last action was the transmission of the slave address we are to write to. */
\r
88 eSentAddressForRead, /*<< Last action was the transmission of the slave address we are to read from. */
\r
89 eSentData, /*<< Last action was the transmission of a data byte. */
\r
90 eReceiveData /*<< We expected data to be received. */
\r
92 /*-----------------------------------------------------------*/
\r
94 /* Points to the message currently being sent. */
\r
95 volatile xI2CMessage *pxCurrentMessage = NULL;
\r
97 /* The queue of messages waiting to be transmitted. */
\r
98 static xQueueHandle xMessagesForTx;
\r
100 /* Flag used to indicate whether or not the ISR is amid sending a message. */
\r
101 unsigned portLONG ulBusFree = ( unsigned portLONG ) pdTRUE;
\r
103 /* Setting this to true will cause the TCP task to think a message is
\r
104 complete and thus restart. It can therefore be used under error states
\r
105 to force a restart. */
\r
106 volatile portLONG lTransactionCompleted = pdTRUE;
\r
108 /*-----------------------------------------------------------*/
\r
110 void vI2CISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxTxMessages, unsigned portLONG **ppulBusFree )
\r
112 /* Create the queues used to hold Rx and Tx characters. */
\r
113 xMessagesForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( xI2CMessage * ) );
\r
115 /* Pass back a reference to the queue and bus free flag so the I2C API file
\r
116 can post messages. */
\r
117 *pxTxMessages = xMessagesForTx;
\r
118 *ppulBusFree = &ulBusFree;
\r
120 /*-----------------------------------------------------------*/
\r
122 /* The ISR entry point. */
\r
123 void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));
\r
125 /* The ISR function to perform the actual work. This must be a separate
\r
126 function from the wrapper to ensure the correct stack frame is set up. */
\r
127 void vI2C_ISR_Handler( void );
\r
129 /*-----------------------------------------------------------*/
\r
131 void vI2C_ISR_Wrapper( void )
\r
133 /* Save the context of the interrupted task. */
\r
134 portSAVE_CONTEXT();
\r
136 /* Call the handler to perform the actual work. This must be a
\r
137 separate function to ensure the correct stack frame is set up. */
\r
138 vI2C_ISR_Handler();
\r
140 /* Restore the context of whichever task is going to run next. */
\r
141 portRESTORE_CONTEXT();
\r
143 /*-----------------------------------------------------------*/
\r
145 void vI2C_ISR_Handler( void )
\r
147 /* Holds the current transmission state. */
\r
148 static I2C_STATE eCurrentState = eSentStart;
\r
149 static portLONG lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */
\r
150 portBASE_TYPE xTaskWokenByTx = pdFALSE;
\r
151 portLONG lBytesLeft;
\r
153 /* The action taken for this interrupt depends on our current state. */
\r
154 switch( eCurrentState )
\r
158 /* We sent a start bit, if it was successful we can
\r
159 go on to send the slave address. */
\r
160 if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )
\r
162 /* Send the slave address. */
\r
163 I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;
\r
165 if( pxCurrentMessage->ucSlaveAddress & i2cREAD )
\r
167 /* We are then going to read bytes back from the
\r
169 eCurrentState = eSentAddressForRead;
\r
171 /* Initialise the buffer index so the first byte goes
\r
172 into the first buffer position. */
\r
177 /* We are then going to write some data to the slave. */
\r
178 eCurrentState = eSentAddressForWrite;
\r
180 /* When writing bytes we first have to send the two
\r
181 byte buffer address so lMessageIndex is set negative,
\r
182 when it reaches 0 it is time to send the actual data. */
\r
183 lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;
\r
188 /* Could not send the start bit so give up. */
\r
189 i2cEND_TRANSMISSION( pdFAIL );
\r
192 I2C_I2CONCLR = i2cSTA_BIT;
\r
196 case eSentAddressForWrite :
\r
198 /* We sent the address of the slave we are going to write to.
\r
199 If this was acknowledged we can go on to send the data. */
\r
200 if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )
\r
202 /* Start the first byte transmitting which is the
\r
203 first byte of the buffer address to which the data will
\r
205 I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;
\r
206 eCurrentState = eSentData;
\r
210 /* Address was not acknowledged so give up. */
\r
211 i2cEND_TRANSMISSION( pdFAIL );
\r
215 case eSentAddressForRead :
\r
217 /* We sent the address of the slave we are going to read from.
\r
218 If this was acknowledged we can go on to read the data. */
\r
219 if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )
\r
221 eCurrentState = eReceiveData;
\r
222 if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )
\r
224 /* Don't ack the last byte of the message. */
\r
225 I2C_I2CONSET = i2cAA_BIT;
\r
230 /* Something unexpected happened - give up. */
\r
231 i2cEND_TRANSMISSION( pdFAIL );
\r
235 case eReceiveData :
\r
237 /* We have just received a byte from the slave. */
\r
238 if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )
\r
240 /* Buffer the byte just received then increment the index
\r
241 so it points to the next free space. */
\r
242 pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;
\r
245 /* How many more bytes are we expecting to receive? */
\r
246 lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;
\r
247 if( lBytesLeft == ( unsigned portLONG ) 0 )
\r
249 /* This was the last byte in the message. */
\r
250 i2cEND_TRANSMISSION( pdPASS );
\r
252 /* If xMessageCompleteSemaphore is not null then there
\r
253 is a task waiting for this message to complete and we
\r
254 must 'give' the semaphore so the task is woken.*/
\r
255 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
257 xTaskWokenByTx = xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, xTaskWokenByTx );
\r
260 /* Are there any other messages to transact? */
\r
261 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xTaskWokenByTx ) == pdTRUE )
\r
263 /* Start the next message - which was
\r
264 retrieved from the queue. */
\r
265 I2C_I2CONSET = i2cSTA_BIT;
\r
269 /* No more messages were found to be waiting for
\r
270 transaction so the bus is free. */
\r
271 ulBusFree = ( unsigned portLONG ) pdTRUE;
\r
276 /* There are more bytes to receive but don't ack the
\r
278 if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )
\r
280 I2C_I2CONCLR = i2cAA_BIT;
\r
286 /* Something unexpected happened - give up. */
\r
287 i2cEND_TRANSMISSION( pdFAIL );
\r
294 /* We sent a data byte, if successful send the next byte in
\r
296 if( I2C_I2STAT == i2cSTATUS_DATA_TXED )
\r
298 /* Index to the next byte to send. */
\r
300 if( lMessageIndex < 0 )
\r
302 /* lMessage index is still negative so we have so far
\r
303 only sent the first byte of the buffer address. Send
\r
304 the second byte now, then initialise the buffer index
\r
305 to zero so the next byte sent comes from the actual
\r
307 I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;
\r
309 else if( lMessageIndex < pxCurrentMessage->lMessageLength )
\r
311 /* Simply send the next byte in the tx buffer. */
\r
312 I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];
\r
316 /* No more bytes in this message to be send. Finished
\r
317 sending message - send a stop bit. */
\r
318 i2cEND_TRANSMISSION( pdPASS );
\r
320 /* If xMessageCompleteSemaphore is not null then there
\r
321 is a task waiting for this message to be sent and the
\r
322 semaphore must be 'given' to wake the task. */
\r
323 if( pxCurrentMessage->xMessageCompleteSemaphore )
\r
325 xTaskWokenByTx = xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, xTaskWokenByTx );
\r
328 /* Are there any other messages to transact? */
\r
329 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xTaskWokenByTx ) == pdTRUE )
\r
331 /* Start the next message from the Tx queue. */
\r
332 I2C_I2CONSET = i2cSTA_BIT;
\r
336 /* No more message were queues for transaction so
\r
337 the bus is free. */
\r
338 ulBusFree = ( unsigned portLONG ) pdTRUE;
\r
344 /* Something unexpected happened, give up. */
\r
345 i2cEND_TRANSMISSION( pdFAIL );
\r
351 /* Should never get here. */
\r
352 eCurrentState = eSentStart;
\r
356 /* Clear the interrupt. */
\r
357 I2C_I2CONCLR = i2cSI_BIT;
\r
358 VICVectAddr = i2cCLEAR_VIC_INTERRUPT;
\r
360 if( xTaskWokenByTx )
\r
362 portYIELD_FROM_ISR();
\r
365 /*-----------------------------------------------------------*/
\r