]> git.sur5r.net Git - freertos/blob
4f848aff2b112a9d872a1521a4c9806a3393197f
[freertos] /
1 /*\r
2  * FreeRTOS+UDP V1.0.2 (C) 2013 Real Time Engineers ltd.\r
3  * All rights reserved\r
4  *\r
5  * This file is part of the FreeRTOS+UDP distribution.  The FreeRTOS+UDP license\r
6  * terms are different to the FreeRTOS license terms.\r
7  *\r
8  * FreeRTOS+UDP uses a dual license model that allows the software to be used\r
9  * under a pure GPL open source license (as opposed to the modified GPL license\r
10  * under which FreeRTOS is distributed) or a commercial license.  Details of\r
11  * both license options follow:\r
12  *\r
13  * - Open source licensing -\r
14  * FreeRTOS+UDP is a free download and may be used, modified, evaluated and\r
15  * distributed without charge provided the user adheres to version two of the\r
16  * GNU General Public License (GPL) and does not remove the copyright notice or\r
17  * this text.  The GPL V2 text is available on the gnu.org web site, and on the\r
18  * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.\r
19  *\r
20  * - Commercial licensing -\r
21  * Businesses and individuals that for commercial or other reasons cannot comply\r
22  * with the terms of the GPL V2 license must obtain a commercial license before\r
23  * incorporating FreeRTOS+UDP into proprietary software for distribution in any\r
24  * form.  Commercial licenses can be purchased from http://shop.freertos.org/udp\r
25  * and do not require any source files to be changed.\r
26  *\r
27  * FreeRTOS+UDP is distributed in the hope that it will be useful.  You cannot\r
28  * use FreeRTOS+UDP unless you agree that you use the software 'as is'.\r
29  * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied\r
30  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
31  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
32  * implied, expressed, or statutory.\r
33  *\r
34  * 1 tab == 4 spaces!\r
35  *\r
36  * http://www.FreeRTOS.org\r
37  * http://www.FreeRTOS.org/udp\r
38  *\r
39  */\r
40 \r
41 /* Standard includes. */\r
42 #include <stdint.h>\r
43 \r
44 /* FreeRTOS includes. */\r
45 #include "FreeRTOS.h"\r
46 #include "task.h"\r
47 #include "queue.h"\r
48 #include "semphr.h"\r
49 \r
50 /* FreeRTOS+UDP includes. */\r
51 #include "FreeRTOS_UDP_IP.h"\r
52 #include "FreeRTOS_IP_Private.h"\r
53 #include "FreeRTOS_Sockets.h"\r
54 #include "NetworkBufferManagement.h"\r
55 \r
56 /* Driver includes. */\r
57 #include "lpc18xx_emac.h"\r
58 \r
59 /* Demo includes. */\r
60 #include "NetworkInterface.h"\r
61 \r
62 #ifndef configNUM_RX_ETHERNET_DMA_DESCRIPTORS\r
63         #error configNUM_RX_ETHERNET_DMA_DESCRIPTORS must be defined in FreeRTOSConfig.h to set the number of RX DMA descriptors\r
64 #endif\r
65 \r
66 #ifndef configNUM_TX_ETHERNET_DMA_DESCRIPTORS\r
67         #error configNUM_TX_ETHERNET_DMA_DESCRIPTORS must be defined in FreeRTOSConfig.h to set the number of TX DMA descriptors\r
68 #endif\r
69 \r
70 /* If a packet cannot be sent immediately then the task performing the send\r
71 operation will be held in the Blocked state (so other tasks can execute) for\r
72 niTX_BUFFER_FREE_WAIT ticks.  It will do this a maximum of niMAX_TX_ATTEMPTS\r
73 before giving up. */\r
74 #define niTX_BUFFER_FREE_WAIT   ( ( portTickType ) 2UL / portTICK_RATE_MS )\r
75 #define niMAX_TX_ATTEMPTS               ( 5 )\r
76 \r
77 /*-----------------------------------------------------------*/\r
78 \r
79 /*\r
80  * A deferred interrupt handler task that processes received frames.\r
81  */\r
82 static void prvEMACDeferredInterruptHandlerTask( void *pvParameters );\r
83 \r
84 /*-----------------------------------------------------------*/\r
85 \r
86 /* The queue used to communicate Ethernet events to the IP task. */\r
87 extern xQueueHandle xNetworkEventQueue;\r
88 \r
89 /* The semaphore used to wake the deferred interrupt handler task when an Rx\r
90 interrupt is received. */\r
91 static xSemaphoreHandle xEMACRxEventSemaphore = NULL;\r
92 \r
93 /*-----------------------------------------------------------*/\r
94 \r
95 portBASE_TYPE xNetworkInterfaceInitialise( void )\r
96 {\r
97 EMAC_CFG_Type Emac_Config;\r
98 portBASE_TYPE xReturn;\r
99 extern uint8_t ucMACAddress[ 6 ];\r
100 \r
101         Emac_Config.pbEMAC_Addr = ucMACAddress;\r
102         xReturn = EMAC_Init( &Emac_Config );\r
103 \r
104         if( xReturn == pdPASS )\r
105         {\r
106                 LPC_ETHERNET->DMA_INT_EN =  DMA_INT_NOR_SUM | DMA_INT_RECEIVE;\r
107 \r
108                 /* Create the event semaphore if it has not already been created. */\r
109                 if( xEMACRxEventSemaphore == NULL )\r
110                 {\r
111                         vSemaphoreCreateBinary( xEMACRxEventSemaphore );\r
112                         #if ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1\r
113                         {\r
114                                 /* If the trace recorder code is included name the semaphore for\r
115                                 viewing in FreeRTOS+Trace. */\r
116                                 vTraceSetQueueName( xEMACRxEventSemaphore, "MAC_RX" );\r
117                         }\r
118                         #endif /*  ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */\r
119                 }\r
120 \r
121                 configASSERT( xEMACRxEventSemaphore );\r
122 \r
123                 /* The Rx deferred interrupt handler task is created at the highest\r
124                 possible priority to ensure the interrupt handler can return directly to\r
125                 it no matter which task was running when the interrupt occurred. */\r
126                 xTaskCreate(    prvEMACDeferredInterruptHandlerTask,            /* The function that implements the task. */\r
127                                                 "MACTsk",\r
128                                                 configMINIMAL_STACK_SIZE,       /* Stack allocated to the task (defined in words, not bytes). */\r
129                                                 NULL,                                           /* The task parameter is not used. */\r
130                                                 configMAX_PRIORITIES - 1,       /* The priority assigned to the task. */\r
131                                                 NULL );                                         /* The handle is not required, so NULL is passed. */\r
132 \r
133                 /* Enable the interrupt and set its priority as configured.  THIS\r
134                 DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, PREFERABLY\r
135                 IN FreeRTOSConfig.h. */\r
136                 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );\r
137                 NVIC_EnableIRQ( ETHERNET_IRQn );\r
138         }\r
139 \r
140         return xReturn;\r
141 }\r
142 /*-----------------------------------------------------------*/\r
143 \r
144 portBASE_TYPE xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
145 {\r
146 portBASE_TYPE xReturn = pdFAIL;\r
147 int32_t x;\r
148 \r
149         /* Attempt to obtain access to a Tx descriptor. */\r
150         for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )\r
151         {\r
152                 if( EMAC_CheckTransmitIndex() == TRUE )\r
153                 {\r
154                         /* Assign the buffer being transmitted to the Tx descriptor. */\r
155                         EMAC_SetNextPacketToSend( pxNetworkBuffer->pucEthernetBuffer );\r
156 \r
157                         /* The EMAC now owns the buffer and will free it when it has been\r
158                         transmitted.  Set pucBuffer to NULL to ensure the buffer is not\r
159                         freed when the network buffer structure is returned to the pool\r
160                         of network buffers. */\r
161                         pxNetworkBuffer->pucEthernetBuffer = NULL;\r
162 \r
163                         /* Initiate the Tx. */\r
164                         EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );\r
165                         iptraceNETWORK_INTERFACE_TRANSMIT();\r
166 \r
167                         /* The Tx has been initiated. */\r
168                         xReturn = pdPASS;\r
169 \r
170                         break;\r
171                 }\r
172                 else\r
173                 {\r
174                         iptraceWAITING_FOR_TX_DMA_DESCRIPTOR();\r
175                         vTaskDelay( niTX_BUFFER_FREE_WAIT );\r
176                 }\r
177         }\r
178 \r
179         /* Finished with the network buffer. */\r
180         vNetworkBufferRelease( pxNetworkBuffer );\r
181 \r
182         return xReturn;\r
183 }\r
184 /*-----------------------------------------------------------*/\r
185 \r
186 void ETH_IRQHandler( void )\r
187 {\r
188 uint32_t ulInterruptCause;\r
189 \r
190         ulInterruptCause = LPC_ETHERNET->DMA_STAT ;\r
191 \r
192         /* Clear the interrupt. */\r
193         LPC_ETHERNET->DMA_STAT |= ( DMA_INT_NOR_SUM | DMA_INT_RECEIVE );\r
194 \r
195         /* Clear fatal error conditions.  NOTE:  The driver does not clear all\r
196         errors, only those actually experienced.  For future reference, range\r
197         errors are not actually errors so can be ignored. */\r
198         if( ( ulInterruptCause & ( 1 << 13 ) ) != 0U )\r
199         {\r
200                 LPC_ETHERNET->DMA_STAT |= ( 1 << 13 );\r
201         }\r
202 \r
203         /* Unblock the deferred interrupt handler task if the event was an Rx. */\r
204         if( ( ulInterruptCause & DMA_INT_RECEIVE ) != 0UL )\r
205         {\r
206                 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );\r
207         }\r
208 \r
209         /* ulInterruptCause is used for convenience here.  A context switch is\r
210         wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a\r
211         compiler warning. */\r
212         portEND_SWITCHING_ISR( ulInterruptCause );\r
213 }\r
214 /*-----------------------------------------------------------*/\r
215 \r
216 static void prvEMACDeferredInterruptHandlerTask( void *pvParameters )\r
217 {\r
218 xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
219 xIPStackEvent_t xRxEvent = { eEthernetRxEvent, NULL };\r
220 \r
221         ( void ) pvParameters;\r
222         configASSERT( xEMACRxEventSemaphore );\r
223 \r
224         for( ;; )\r
225         {\r
226                 /* Wait for the EMAC interrupt to indicate that another packet has been\r
227                 received.  The while() loop is only needed if INCLUDE_vTaskSuspend is\r
228                 set to 0 in FreeRTOSConfig.h.  If INCLUDE_vTaskSuspend is set to 1\r
229                 then portMAX_DELAY would be an indefinite block time and\r
230                 xSemaphoreTake() would only return when the semaphore was actually\r
231                 obtained. */\r
232                 while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );\r
233 \r
234                 /* At least one packet has been received. */\r
235                 while( EMAC_CheckReceiveIndex() != FALSE )\r
236                 {\r
237                         /* The buffer filled by the DMA is going to be passed into the IP\r
238                         stack.  Allocate another buffer for the DMA descriptor. */\r
239                         pxNetworkBuffer = pxNetworkBufferGet( ipTOTAL_ETHERNET_FRAME_SIZE, ( portTickType ) 0 );\r
240 \r
241                         if( pxNetworkBuffer != NULL )\r
242                         {\r
243                                 /* Swap the buffer just allocated and referenced from the\r
244                                 pxNetworkBuffer with the buffer that has already been filled by\r
245                                 the DMA.  pxNetworkBuffer will then hold a reference to the\r
246                                 buffer that already contains the data without any data having\r
247                                 been copied between buffers. */\r
248                                 EMAC_NextPacketToRead( pxNetworkBuffer );\r
249 \r
250                                 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 1\r
251                                 {\r
252                                         if( pxNetworkBuffer->xDataLength > 0 )\r
253                                         {\r
254                                                 /* If the frame would not be processed by the IP stack then\r
255                                                 don't even bother sending it to the IP stack. */\r
256                                                 if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) != eProcessBuffer )\r
257                                                 {\r
258                                                         pxNetworkBuffer->xDataLength = 0;\r
259                                                 }\r
260                                         }\r
261                                 }\r
262                                 #endif\r
263 \r
264                                 if( pxNetworkBuffer->xDataLength > 0 )\r
265                                 {\r
266                                         /* Store a pointer to the network buffer structure in the\r
267                                         padding space that was left in front of the Ethernet frame.\r
268                                         The pointer     is needed to ensure the network buffer structure\r
269                                         can be located when it is time for it to be freed if the\r
270                                         Ethernet frame gets     used as a zero copy buffer. */\r
271                                         *( ( xNetworkBufferDescriptor_t ** ) ( ( pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING ) ) ) = pxNetworkBuffer;\r
272 \r
273                                         /* Data was received and stored.  Send it to the IP task\r
274                                         for processing. */\r
275                                         xRxEvent.pvData = ( void * ) pxNetworkBuffer;\r
276                                         if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, ( portTickType ) 0 ) == pdFALSE )\r
277                                         {\r
278                                                 /* The buffer could not be sent to the IP task so the\r
279                                                 buffer must be released. */\r
280                                                 vNetworkBufferRelease( pxNetworkBuffer );\r
281                                                 iptraceETHERNET_RX_EVENT_LOST();\r
282                                         }\r
283                                         else\r
284                                         {\r
285                                                 iptraceNETWORK_INTERFACE_RECEIVE();\r
286                                         }\r
287                                 }\r
288                                 else\r
289                                 {\r
290                                         /* The buffer does not contain any data so there is no\r
291                                         point sending it to the IP task.  Just release it. */\r
292                                         vNetworkBufferRelease( pxNetworkBuffer );\r
293                                         iptraceETHERNET_RX_EVENT_LOST();\r
294                                 }\r
295                         }\r
296                         else\r
297                         {\r
298                                 iptraceETHERNET_RX_EVENT_LOST();\r
299                         }\r
300 \r
301                         /* Release the descriptor. */\r
302                         EMAC_UpdateRxConsumeIndex();\r
303                 }\r
304         }\r
305 }\r
306 /*-----------------------------------------------------------*/\r
307 \r