]> git.sur5r.net Git - freertos/blob - Demo/WizNET_DEMO_GCC_ARM7/i2cISR.c
Prepare for V5.3.1 release.
[freertos] / Demo / WizNET_DEMO_GCC_ARM7 / i2cISR.c
1 /*\r
2         FreeRTOS.org V5.3.1 - Copyright (C) 2003-2009 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify it\r
7         under the terms of the GNU General Public License (version 2) as published\r
8         by the Free Software Foundation and modified by the FreeRTOS exception.\r
9         **NOTE** The exception to the GPL is included to allow you to distribute a\r
10         combined work that includes FreeRTOS.org without being obliged to provide\r
11         the source code for any proprietary components.  Alternative commercial\r
12         license and support terms are also available upon request.  See the \r
13         licensing section of http://www.FreeRTOS.org for full details.\r
14 \r
15         FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT\r
16         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
17         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
18         more details.\r
19 \r
20         You should have received a copy of the GNU General Public License along\r
21         with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59\r
22         Temple Place, Suite 330, Boston, MA  02111-1307  USA.\r
23 \r
24 \r
25         ***************************************************************************\r
26         *                                                                         *\r
27         * Get the FreeRTOS eBook!  See http://www.FreeRTOS.org/Documentation      *\r
28         *                                                                         *\r
29         * This is a concise, step by step, 'hands on' guide that describes both   *\r
30         * general multitasking concepts and FreeRTOS specifics. It presents and   *\r
31         * explains numerous examples that are written using the FreeRTOS API.     *\r
32         * Full source code for all the examples is provided in an accompanying    *\r
33         * .zip file.                                                              *\r
34         *                                                                         *\r
35         ***************************************************************************\r
36 \r
37         1 tab == 4 spaces!\r
38 \r
39         Please ensure to read the configuration and relevant port sections of the\r
40         online documentation.\r
41 \r
42         http://www.FreeRTOS.org - Documentation, latest information, license and\r
43         contact details.\r
44 \r
45         http://www.SafeRTOS.com - A version that is certified for use in safety\r
46         critical systems.\r
47 \r
48         http://www.OpenRTOS.com - Commercial support, development, porting,\r
49         licensing and training services.\r
50 */\r
51 \r
52 \r
53 /* Standard includes. */\r
54 #include <stdlib.h>\r
55 \r
56 /* Scheduler include files. */\r
57 #include "FreeRTOS.h"\r
58 #include "task.h"\r
59 #include "queue.h"\r
60 #include "semphr.h"\r
61 \r
62 /* Application includes. */\r
63 #include "i2c.h"\r
64 \r
65 /*-----------------------------------------------------------*/\r
66 \r
67 /* Bit definitions within the I2CONCLR register. */\r
68 #define i2cSTA_BIT              ( ( unsigned portCHAR ) 0x20 )\r
69 #define i2cSI_BIT               ( ( unsigned portCHAR ) 0x08 )\r
70 #define i2cSTO_BIT              ( ( unsigned portCHAR ) 0x10 )\r
71 #define i2cAA_BIT               ( ( unsigned portCHAR ) 0x04 )\r
72 \r
73 /* Status codes for the I2STAT register. */\r
74 #define i2cSTATUS_START_TXED                    ( 0x08 )\r
75 #define i2cSTATUS_REP_START_TXED                ( 0x10 )\r
76 #define i2cSTATUS_TX_ADDR_ACKED                 ( 0x18 )\r
77 #define i2cSTATUS_DATA_TXED                             ( 0x28 )\r
78 #define i2cSTATUS_RX_ADDR_ACKED                 ( 0x40 )\r
79 #define i2cSTATUS_DATA_RXED                             ( 0x50 )\r
80 #define i2cSTATUS_LAST_BYTE_RXED                ( 0x58 )\r
81 \r
82 /* Constants for operation of the VIC. */\r
83 #define i2cCLEAR_VIC_INTERRUPT  ( 0 )\r
84 \r
85 /* Misc constants. */\r
86 #define i2cJUST_ONE_BYTE_TO_RX  ( 1 )\r
87 #define i2cBUFFER_ADDRESS_BYTES ( 2 )\r
88 \r
89 /* End the current transmission and free the bus. */\r
90 #define i2cEND_TRANSMISSION( lStatus )                                  \\r
91 {                                                                                                               \\r
92         I2C_I2CONCLR = i2cAA_BIT;                                                       \\r
93         I2C_I2CONSET = i2cSTO_BIT;                                                      \\r
94         eCurrentState = eSentStart;                                                     \\r
95         lTransactionCompleted = lStatus;                                        \\r
96 }\r
97 /*-----------------------------------------------------------*/\r
98 \r
99 /* Valid i2c communication states. */\r
100 typedef enum\r
101 {\r
102         eSentStart,                             /*<< Last action was the transmission of a start bit. */\r
103         eSentAddressForWrite,   /*<< Last action was the transmission of the slave address we are to write to. */\r
104         eSentAddressForRead,    /*<< Last action was the transmission of the slave address we are to read from. */\r
105         eSentData,                              /*<< Last action was the transmission of a data byte. */\r
106         eReceiveData                    /*<< We expected data to be received. */\r
107 } I2C_STATE;\r
108 /*-----------------------------------------------------------*/\r
109 \r
110 /* Points to the message currently being sent. */\r
111 volatile xI2CMessage *pxCurrentMessage = NULL;  \r
112 \r
113 /* The queue of messages waiting to be transmitted. */\r
114 static xQueueHandle xMessagesForTx;\r
115 \r
116 /* Flag used to indicate whether or not the ISR is amid sending a message. */\r
117 unsigned portLONG ulBusFree = ( unsigned portLONG ) pdTRUE;\r
118 \r
119 /* Setting this to true will cause the TCP task to think a message is \r
120 complete and thus restart.  It can therefore be used under error states\r
121 to force a restart. */\r
122 volatile portLONG lTransactionCompleted = pdTRUE;\r
123 \r
124 /*-----------------------------------------------------------*/\r
125 \r
126 void vI2CISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxTxMessages, unsigned portLONG **ppulBusFree )\r
127 {\r
128         /* Create the queues used to hold Rx and Tx characters. */\r
129         xMessagesForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( xI2CMessage * ) );\r
130 \r
131         /* Pass back a reference to the queue and bus free flag so the I2C API file \r
132         can post messages. */\r
133         *pxTxMessages = xMessagesForTx;\r
134         *ppulBusFree = &ulBusFree;\r
135 }\r
136 /*-----------------------------------------------------------*/\r
137 \r
138 /* The ISR entry point. */\r
139 void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));\r
140 \r
141 /* The ISR function to perform the actual work.  This must be a separate\r
142 function from the wrapper to ensure the correct stack frame is set up. */\r
143 void vI2C_ISR_Handler( void );\r
144 \r
145 /*-----------------------------------------------------------*/\r
146 \r
147 void vI2C_ISR_Wrapper( void )\r
148 {\r
149         /* Save the context of the interrupted task. */\r
150         portSAVE_CONTEXT();\r
151 \r
152         /* Call the handler to perform the actual work.  This must be a\r
153         separate function to ensure the correct stack frame is set up. */\r
154         vI2C_ISR_Handler();\r
155 \r
156         /* Restore the context of whichever task is going to run next. */\r
157         portRESTORE_CONTEXT();\r
158 }\r
159 /*-----------------------------------------------------------*/\r
160 \r
161 void vI2C_ISR_Handler( void )\r
162 {\r
163 /* Holds the current transmission state. */                                                     \r
164 static I2C_STATE eCurrentState = eSentStart;\r
165 static portLONG lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */\r
166 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
167 portLONG lBytesLeft;\r
168 \r
169         /* The action taken for this interrupt depends on our current state. */\r
170         switch( eCurrentState )\r
171         {\r
172                 case eSentStart :       \r
173 \r
174                                 /* We sent a start bit, if it was successful we can\r
175                                 go on to send the slave address. */\r
176                                 if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )\r
177                                 {\r
178                                         /* Send the slave address. */\r
179                                         I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;\r
180 \r
181                                         if( pxCurrentMessage->ucSlaveAddress & i2cREAD )\r
182                                         {\r
183                                                 /* We are then going to read bytes back from the \r
184                                                 slave. */\r
185                                                 eCurrentState = eSentAddressForRead;\r
186                                                 \r
187                                                 /* Initialise the buffer index so the first byte goes\r
188                                                 into the first buffer position. */\r
189                                                 lMessageIndex = 0;\r
190                                         }\r
191                                         else\r
192                                         {\r
193                                                 /* We are then going to write some data to the slave. */\r
194                                                 eCurrentState = eSentAddressForWrite;\r
195 \r
196                                                 /* When writing bytes we first have to send the two\r
197                                                 byte buffer address so lMessageIndex is set negative,\r
198                                                 when it reaches 0 it is time to send the actual data. */\r
199                                                 lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;\r
200                                         }\r
201                                 }\r
202                                 else\r
203                                 {\r
204                                         /* Could not send the start bit so give up. */\r
205                                         i2cEND_TRANSMISSION( pdFAIL );                                  \r
206                                 }\r
207 \r
208                                 I2C_I2CONCLR = i2cSTA_BIT;                              \r
209 \r
210                                 break;\r
211 \r
212                 case eSentAddressForWrite :\r
213 \r
214                                 /* We sent the address of the slave we are going to write to.\r
215                                 If this was acknowledged we     can go on to send the data. */\r
216                                 if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )\r
217                                 {\r
218                                         /* Start the first byte transmitting which is the \r
219                                         first byte of the buffer address to which the data will \r
220                                         be sent. */\r
221                                         I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;\r
222                                         eCurrentState = eSentData;\r
223                                 }\r
224                                 else\r
225                                 {\r
226                                         /* Address was not acknowledged so give up. */\r
227                                         i2cEND_TRANSMISSION( pdFAIL );                                  \r
228                                 }                                       \r
229                                 break;\r
230 \r
231                 case eSentAddressForRead :\r
232 \r
233                                 /* We sent the address of the slave we are going to read from.\r
234                                 If this was acknowledged we can go on to read the data. */\r
235                                 if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )\r
236                                 {\r
237                                         eCurrentState = eReceiveData;\r
238                                         if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )\r
239                                         {\r
240                                                 /* Don't ack the last byte of the message. */\r
241                                                 I2C_I2CONSET = i2cAA_BIT;\r
242                                         }                                       \r
243                                 }\r
244                                 else\r
245                                 {\r
246                                         /* Something unexpected happened - give up. */\r
247                                         i2cEND_TRANSMISSION( pdFAIL );                                  \r
248                                 }\r
249                                 break;\r
250 \r
251                 case eReceiveData :\r
252                                 \r
253                                 /* We have just received a byte from the slave. */\r
254                                 if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )\r
255                                 {\r
256                                         /* Buffer the byte just received then increment the index \r
257                                         so it points to the next free space. */\r
258                                         pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;\r
259                                         lMessageIndex++;\r
260 \r
261                                         /* How many more bytes are we expecting to receive? */\r
262                                         lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;\r
263                                         if( lBytesLeft == ( unsigned portLONG ) 0 )\r
264                                         {\r
265                                                 /* This was the last byte in the message. */\r
266                                                 i2cEND_TRANSMISSION( pdPASS );\r
267 \r
268                                                 /* If xMessageCompleteSemaphore is not null then there\r
269                                                 is a task waiting for this message to complete and we\r
270                                                 must 'give' the semaphore so the task is woken.*/\r
271                                                 if( pxCurrentMessage->xMessageCompleteSemaphore )\r
272                                                 {\r
273                                                         xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );\r
274                                                 }\r
275 \r
276                                                 /* Are there any other messages to transact? */\r
277                                                 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )\r
278                                                 {\r
279                                                         /* Start the next message - which was\r
280                                                         retrieved from the queue. */\r
281                                                         I2C_I2CONSET = i2cSTA_BIT;\r
282                                                 }\r
283                                                 else\r
284                                                 {\r
285                                                         /* No more messages were found to be waiting for\r
286                                                         transaction so the bus is free. */\r
287                                                         ulBusFree = ( unsigned portLONG ) pdTRUE;                       \r
288                                                 }                                               \r
289                                         }\r
290                                         else\r
291                                         {\r
292                                                 /* There are more bytes to receive but don't ack the \r
293                                                 last byte. */\r
294                                                 if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )\r
295                                                 {\r
296                                                         I2C_I2CONCLR = i2cAA_BIT;\r
297                                                 }                                                        \r
298                                         }\r
299                                 }\r
300                                 else\r
301                                 {\r
302                                         /* Something unexpected happened - give up. */\r
303                                         i2cEND_TRANSMISSION( pdFAIL );                                  \r
304                                 }\r
305 \r
306                                 break;\r
307                                 \r
308                 case eSentData  :       \r
309 \r
310                                 /* We sent a data byte, if successful send the  next byte in \r
311                                 the message. */\r
312                                 if( I2C_I2STAT == i2cSTATUS_DATA_TXED )\r
313                                 {\r
314                                         /* Index to the next byte to send. */\r
315                                         lMessageIndex++;\r
316                                         if( lMessageIndex < 0 )\r
317                                         {\r
318                                                 /* lMessage index is still negative so we have so far \r
319                                                 only sent the first byte of the buffer address.  Send \r
320                                                 the second byte now, then initialise the buffer index\r
321                                                 to zero so the next byte sent comes from the actual \r
322                                                 data buffer. */\r
323                                                 I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;\r
324                                         }\r
325                                         else if( lMessageIndex < pxCurrentMessage->lMessageLength )\r
326                                         {\r
327                                                 /* Simply send the next byte in the tx buffer. */\r
328                                                 I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];                                                                               \r
329                                         }\r
330                                         else\r
331                                         {\r
332                                                 /* No more bytes in this message to be send.  Finished \r
333                                                 sending message - send a stop bit. */\r
334                                                 i2cEND_TRANSMISSION( pdPASS );\r
335 \r
336                                                 /* If xMessageCompleteSemaphore is not null then there\r
337                                                 is a task waiting for this message to be sent and the\r
338                                                 semaphore must be 'given' to wake the task. */\r
339                                                 if( pxCurrentMessage->xMessageCompleteSemaphore )\r
340                                                 {\r
341                                                         xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );\r
342                                                 }\r
343 \r
344                                                 /* Are there any other messages to transact? */\r
345                                                 if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )\r
346                                                 {\r
347                                                         /* Start the next message from the Tx queue. */\r
348                                                         I2C_I2CONSET = i2cSTA_BIT;\r
349                                                 }\r
350                                                 else\r
351                                                 {\r
352                                                         /* No more message were queues for transaction so \r
353                                                         the bus is free. */\r
354                                                         ulBusFree = ( unsigned portLONG ) pdTRUE;                       \r
355                                                 }\r
356                                         }\r
357                                 }\r
358                                 else\r
359                                 {\r
360                                         /* Something unexpected happened, give up. */\r
361                                         i2cEND_TRANSMISSION( pdFAIL );                                  \r
362                                 }\r
363                                 break;\r
364 \r
365                 default :       \r
366                 \r
367                                 /* Should never get here. */\r
368                                 eCurrentState = eSentStart;\r
369                                 break;\r
370         }       \r
371 \r
372         /* Clear the interrupt. */\r
373         I2C_I2CONCLR = i2cSI_BIT;\r
374         VICVectAddr = i2cCLEAR_VIC_INTERRUPT;\r
375 \r
376         if( xHigherPriorityTaskWoken )\r
377         {\r
378                 portYIELD_FROM_ISR();\r
379         }\r
380 }\r
381 /*-----------------------------------------------------------*/\r
382 \r