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