]> git.sur5r.net Git - freertos/blob
c6e286ed0015ab0d7a963ec01e61ec01a6f68a69
[freertos] /
1 /*\r
2  * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.\r
3  *\r
4  * This file is part of the FreeRTOS+UDP distribution.  The FreeRTOS+UDP license\r
5  * terms are different to the FreeRTOS license terms.\r
6  *\r
7  * FreeRTOS+UDP uses a dual license model that allows the software to be used \r
8  * under a standard GPL open source license, or a commercial license.  The \r
9  * standard GPL license (unlike the modified GPL license under which FreeRTOS \r
10  * itself is distributed) requires that all software statically linked with \r
11  * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.  \r
12  * Details of both license options follow:\r
13  *\r
14  * - Open source licensing -\r
15  * FreeRTOS+UDP is a free download and may be used, modified, evaluated and\r
16  * distributed without charge provided the user adheres to version two of the\r
17  * GNU General Public License (GPL) and does not remove the copyright notice or\r
18  * this text.  The GPL V2 text is available on the gnu.org web site, and on the\r
19  * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.\r
20  *\r
21  * - Commercial licensing -\r
22  * Businesses and individuals that for commercial or other reasons cannot comply\r
23  * with the terms of the GPL V2 license must obtain a commercial license before \r
24  * incorporating FreeRTOS+UDP into proprietary software for distribution in any \r
25  * form.  Commercial licenses can be purchased from http://shop.freertos.org/udp \r
26  * and do not require any source files to be changed.\r
27  *\r
28  * FreeRTOS+UDP is distributed in the hope that it will be useful.  You cannot\r
29  * use FreeRTOS+UDP unless you agree that you use the software 'as is'.\r
30  * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied\r
31  * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
32  * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
33  * implied, expressed, or statutory.\r
34  *\r
35  * 1 tab == 4 spaces!\r
36  *\r
37  * http://www.FreeRTOS.org\r
38  * http://www.FreeRTOS.org/udp\r
39  *\r
40  */\r
41  \r
42 /* FreeRTOS includes. */\r
43 #include "FreeRTOS.h"\r
44 #include "task.h"\r
45 #include "semphr.h"\r
46 \r
47 /* FreeRTOS+UDP includes. */\r
48 #include "FreeRTOS_UDP_IP.h"\r
49 #include "FreeRTOS_IP_Private.h"\r
50 #include "NetworkBufferManagement.h"\r
51 \r
52 /* Library includes. */\r
53 #include "board.h"\r
54 \r
55 /* Descriptors that reference received buffers are expected to have both the\r
56 first and last frame bits set because buffers are dimensioned to hold complete\r
57 Ethernet frames. */\r
58 #define emacEXPECTED_RX_STATUS_MASK     ( RDES_LS | RDES_FS )\r
59 \r
60 /*-----------------------------------------------------------*/\r
61 \r
62 /*\r
63  * Set the Rx and Tx descriptors into their expected initial state.\r
64  */\r
65 static void prvResetRxDescriptors( void );\r
66 static void prvResetTxDescriptors( void );\r
67 \r
68 /*\r
69  * Returns the length of the data pointed to by the next Rx descriptor.\r
70  */\r
71 static uint32_t prvReceivedDataLength( void );\r
72 \r
73 \r
74 /*-----------------------------------------------------------*/\r
75 \r
76 /* Rx and Tx descriptors and data array. */\r
77 static volatile IP_ENET_001_ENHRXDESC_T xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS ];\r
78 static volatile IP_ENET_001_ENHTXDESC_T xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS ];\r
79 \r
80 /* Indexes into the Rx and Tx descriptor arrays. */\r
81 static unsigned int xRxDescriptorIndex = 0;\r
82 static unsigned int xTxDescriptorIndex = 0;\r
83 \r
84 /*-----------------------------------------------------------*/\r
85 \r
86 portBASE_TYPE xEMACInit( uint8_t ucMACAddress[ 6 ] )\r
87 {\r
88 portBASE_TYPE xReturn;\r
89 uint32_t ulPHYStatus;\r
90 \r
91         /* Configure the hardware. */\r
92         Chip_ENET_Init( LPC_ETHERNET );\r
93 \r
94         if( lpc_phy_init( pdTRUE, vTaskDelay ) == SUCCESS )\r
95         {\r
96                 /* The MAC address is passed in as the function parameter. */\r
97                 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );\r
98 \r
99                 /* Wait for autonegotiation to complete. */\r
100                 do\r
101                 {\r
102                         vTaskDelay( 100 );\r
103                         ulPHYStatus = lpcPHYStsPoll();\r
104                 } while( ( ulPHYStatus & PHY_LINK_CONNECTED ) == 0x00 );\r
105 \r
106                 /* Configure the hardware as per the negotiated link. */\r
107                 if( ( ulPHYStatus & PHY_LINK_FULLDUPLX ) == PHY_LINK_FULLDUPLX )\r
108                 {\r
109                         IP_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );\r
110                 }\r
111                 else\r
112                 {\r
113                         IP_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );\r
114                 }\r
115 \r
116                 if( ( ulPHYStatus & PHY_LINK_SPEED100 ) == PHY_LINK_SPEED100 )\r
117                 {\r
118                         IP_ENET_SetSpeed( LPC_ETHERNET, pdTRUE );\r
119                 }\r
120                 else\r
121                 {\r
122                         IP_ENET_SetSpeed( LPC_ETHERNET, pdFALSE );\r
123                 }\r
124 \r
125                 /* Set descriptors to their initial state. */\r
126                 prvResetRxDescriptors();\r
127                 prvResetTxDescriptors();\r
128 \r
129                 /* Enable RX and TX. */\r
130                 Chip_ENET_TXEnable( LPC_ETHERNET );\r
131                 Chip_ENET_RXEnable( LPC_ETHERNET );\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                 /* Enable interrupts. */\r
140                 LPC_ETHERNET->DMA_INT_EN =  DMA_IE_NIE | DMA_IE_RIE;\r
141 \r
142                 xReturn = pdPASS;\r
143         }\r
144         else\r
145         {\r
146                 xReturn = pdFAIL;\r
147         }\r
148 \r
149         return xReturn;\r
150 }\r
151 /*-----------------------------------------------------------*/\r
152 \r
153 portBASE_TYPE xEMACIsTxDescriptorAvailable( void )\r
154 {\r
155 portBASE_TYPE xReturn;\r
156 \r
157         if( ( xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT & RDES_OWN ) == 0 )\r
158         {\r
159                 xReturn = pdPASS;\r
160         }\r
161         else\r
162         {\r
163                 xReturn = pdFAIL;\r
164         }\r
165 \r
166         return xReturn;\r
167 }\r
168 /*-----------------------------------------------------------*/\r
169 \r
170 void vEMACAssignBufferToDescriptor( uint8_t * pucBuffer )\r
171 {\r
172         /* The old packet is now finished with and can be freed. */\r
173         vEthernetBufferRelease( ( void * ) xTxDescriptors[ xTxDescriptorIndex ].B1ADD );\r
174 \r
175         /* Assign the new packet to the descriptor. */\r
176         xTxDescriptors[ xTxDescriptorIndex ].B1ADD = ( uint32_t ) pucBuffer;\r
177 }\r
178 /*-----------------------------------------------------------*/\r
179 \r
180 void vEMACStartNextTransmission( uint32_t ulLength )\r
181 {\r
182         xTxDescriptors[ xTxDescriptorIndex ].BSIZE = ulLength;\r
183         xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT |= RDES_OWN;\r
184 \r
185         /* Wake Up the DMA if it's in Suspended Mode. */\r
186         LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;\r
187         xTxDescriptorIndex++;\r
188 \r
189         if( xTxDescriptorIndex == configNUM_TX_ETHERNET_DMA_DESCRIPTORS )\r
190         {\r
191                 xTxDescriptorIndex = 0;\r
192         }\r
193 }\r
194 /*-----------------------------------------------------------*/\r
195 \r
196 static uint32_t prvReceivedDataLength( void )\r
197 {\r
198 unsigned short RxLen = 0;\r
199 \r
200         RxLen = ( xRXDescriptors[ xRxDescriptorIndex ].STATUS >> 16 ) & 0x03FFF;\r
201         return RxLen;\r
202 }\r
203 /*-----------------------------------------------------------*/\r
204 \r
205 void vEMACReturnRxDescriptor( void )\r
206 {\r
207         xRXDescriptors[ xRxDescriptorIndex ].STATUS = RDES_OWN;\r
208         xRxDescriptorIndex++;\r
209 \r
210         if( xRxDescriptorIndex == configNUM_RX_ETHERNET_DMA_DESCRIPTORS )\r
211         {\r
212                 xRxDescriptorIndex = 0;\r
213         }\r
214 }\r
215 /*-----------------------------------------------------------*/\r
216 \r
217 portBASE_TYPE xEMACRxDataAvailable( void )\r
218 {\r
219 portBASE_TYPE xReturn;\r
220 \r
221         if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & RDES_OWN ) == 0 )\r
222         {\r
223                 xReturn = pdPASS;\r
224         }\r
225         else\r
226         {\r
227                 xReturn = pdFAIL;\r
228         }\r
229 \r
230         return xReturn;\r
231 }\r
232 /*-----------------------------------------------------------*/\r
233 \r
234 void vEMACSwapEmptyBufferForRxedData( xNetworkBufferDescriptor_t *pxNetworkBuffer )\r
235 {\r
236 uint8_t *pucTemp;\r
237 \r
238         /* Swap the buffer in the network buffer with the buffer used by the DMA.\r
239         This allows the data to be passed out without having to perform any copies. */\r
240         pucTemp = ( uint8_t * ) xRXDescriptors[ xRxDescriptorIndex ].B1ADD;\r
241         xRXDescriptors[ xRxDescriptorIndex ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;\r
242         pxNetworkBuffer->pucEthernetBuffer = pucTemp;\r
243 \r
244         /* Only supports frames coming in single buffers.  If this frame is split\r
245         across multiple buffers then reject it (and if the frame is needed increase\r
246         the ipconfigNETWORK_MTU setting). */\r
247         if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & emacEXPECTED_RX_STATUS_MASK ) != emacEXPECTED_RX_STATUS_MASK )\r
248         {\r
249                 pxNetworkBuffer->xDataLength = 0;\r
250         }\r
251         else\r
252         {\r
253                 pxNetworkBuffer->xDataLength = ( size_t ) prvReceivedDataLength() - ( ipETHERNET_CRC_BYTES - 1U );;\r
254         }\r
255 }\r
256 /*-----------------------------------------------------------*/\r
257 \r
258 static void prvResetRxDescriptors( void )\r
259 {\r
260 uint32_t x;\r
261 size_t xBufferSize = ipTOTAL_ETHERNET_FRAME_SIZE;\r
262 \r
263         for( x = 0; x < configNUM_RX_ETHERNET_DMA_DESCRIPTORS; x++ )\r
264         {\r
265                 /* Obtain the buffer first, as the size of the buffer might be changed\r
266                 within the pucEthernetBufferGet() call. */\r
267                 xRXDescriptors[ x ].B1ADD  = ( uint32_t ) pucEthernetBufferGet( &xBufferSize );\r
268                 xRXDescriptors[ x ].STATUS = RDES_OWN;\r
269                 xRXDescriptors[ x ].CTRL  = xBufferSize;\r
270                 xRXDescriptors[ x ].B2ADD = ( uint32_t ) &xRXDescriptors[ x + 1 ];\r
271                 \r
272                 configASSERT( ( ( ( uint32_t ) xRXDescriptors[x].B1ADD ) & 0x07 ) == 0 );\r
273         }\r
274 \r
275         /* Last Descriptor */\r
276         xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS - 1 ].CTRL |= RDES_ENH_RER;\r
277 \r
278         xRxDescriptorIndex = 0;\r
279 \r
280         /* Set Starting address of RX Descriptor list */\r
281         LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xRXDescriptors;\r
282 }\r
283 /*-----------------------------------------------------------*/\r
284 \r
285 static void prvResetTxDescriptors( void )\r
286 {\r
287 /* Initialize Transmit Descriptor and Status array. */\r
288 uint32_t x;\r
289 \r
290         for( x = 0; x < configNUM_TX_ETHERNET_DMA_DESCRIPTORS; x++ )\r
291         {\r
292                 xTxDescriptors[ x ].CTRLSTAT = TDES_ENH_FS | TDES_ENH_LS;\r
293                 xTxDescriptors[ x ].BSIZE  = 0;\r
294                 xTxDescriptors[ x ].B2ADD = ( uint32_t ) &xTxDescriptors[ x + 1 ];\r
295 \r
296                 /* Packet is assigned when a Tx is initiated. */\r
297                 xTxDescriptors[ x ].B1ADD   = ( uint32_t )NULL;\r
298         }\r
299 \r
300         /* Last Descriptor? */\r
301         xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS-1 ].CTRLSTAT |= TDES_ENH_TER;\r
302 \r
303         /* Set Starting address of TX Descriptor list */\r
304         LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xTxDescriptors;\r
305 }\r
306 /*-----------------------------------------------------------*/\r
307 \r
308 void ETH_IRQHandler( void )\r
309 {\r
310 uint32_t ulInterruptCause;\r
311 extern xSemaphoreHandle xEMACRxEventSemaphore;\r
312 \r
313         configASSERT( xEMACRxEventSemaphore );\r
314 \r
315         ulInterruptCause = LPC_ETHERNET->DMA_STAT ;\r
316 \r
317         /* Clear the interrupt. */\r
318         LPC_ETHERNET->DMA_STAT |= ( DMA_ST_NIS | DMA_ST_RI );\r
319 \r
320         /* Clear fatal error conditions.  NOTE:  The driver does not clear all\r
321         errors, only those actually experienced.  For future reference, range\r
322         errors are not actually errors so can be ignored. */\r
323         if( ( ulInterruptCause & DMA_ST_FBI ) != 0U )\r
324         {\r
325                 LPC_ETHERNET->DMA_STAT |= DMA_ST_FBI;\r
326         }\r
327 \r
328         /* Unblock the deferred interrupt handler task if the event was an Rx. */\r
329         if( ( ulInterruptCause & DMA_IE_RIE ) != 0UL )\r
330         {\r
331                 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );\r
332         }\r
333 \r
334         /* ulInterruptCause is used for convenience here.  A context switch is\r
335         wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a\r
336         compiler warning. */\r
337         portEND_SWITCHING_ISR( ulInterruptCause );\r
338 }\r
339 \r