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