]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c
7de2902f8a7c741cf166cbe98e0f6afdb23a3d17
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / STM32F7xx / NetworkInterface.c
1 /*\r
2  * Some constants, hardware definitions and comments taken from ST's HAL driver\r
3  * library, COPYRIGHT(c) 2015 STMicroelectronics.\r
4  */\r
5 \r
6 /*\r
7  * FreeRTOS+TCP V2.0.11\r
8  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
9  *\r
10  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
11  * this software and associated documentation files (the "Software"), to deal in\r
12  * the Software without restriction, including without limitation the rights to\r
13  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
14  * the Software, and to permit persons to whom the Software is furnished to do so,\r
15  * subject to the following conditions:\r
16  *\r
17  * The above copyright notice and this permission notice shall be included in all\r
18  * copies or substantial portions of the Software.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
22  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
23  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
26  *\r
27  * http://www.FreeRTOS.org\r
28  * http://aws.amazon.com/freertos\r
29  *\r
30  * 1 tab == 4 spaces!\r
31  */\r
32 \r
33 /* Standard includes. */\r
34 #include <stdint.h>\r
35 #include <stdio.h>\r
36 #include <stdlib.h>\r
37 \r
38 /* FreeRTOS includes. */\r
39 #include "FreeRTOS.h"\r
40 #include "task.h"\r
41 #include "queue.h"\r
42 #include "semphr.h"\r
43 \r
44 /* FreeRTOS+TCP includes. */\r
45 #include "FreeRTOS_IP.h"\r
46 #include "FreeRTOS_Sockets.h"\r
47 #include "FreeRTOS_IP_Private.h"\r
48 #include "FreeRTOS_DNS.h"\r
49 #include "NetworkBufferManagement.h"\r
50 #include "NetworkInterface.h"\r
51 \r
52 #include "phyHandling.h"\r
53 \r
54 /* ST includes. */\r
55 #ifdef STM32F7xx\r
56         #include "stm32f7xx_hal.h"\r
57 #else\r
58         #include "stm32f4xx_hal.h"\r
59 #endif\r
60 \r
61 /* Interrupt events to process.  Currently only the Rx event is processed\r
62 although code for other events is included to allow for possible future\r
63 expansion. */\r
64 #define EMAC_IF_RX_EVENT        1UL\r
65 #define EMAC_IF_TX_EVENT        2UL\r
66 #define EMAC_IF_ERR_EVENT       4UL\r
67 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
68 \r
69 #define ETH_DMA_ALL_INTS \\r
70         ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \\r
71           ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \\r
72           ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )\r
73 \r
74 \r
75 \r
76 #define ipFRAGMENT_OFFSET_BIT_MASK              ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */\r
77 \r
78 /*\r
79  * Most users will want a PHY that negotiates about\r
80  * the connection properties: speed, dmix and duplex.\r
81  * On some rare cases, you want to select what is being\r
82  * advertised, properties like MDIX and duplex.\r
83  */\r
84 \r
85 #if !defined( ipconfigETHERNET_AN_ENABLE )\r
86         /* Enable auto-negotiation */\r
87         #define ipconfigETHERNET_AN_ENABLE                              1\r
88 #endif\r
89 \r
90 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )\r
91         #define ipconfigETHERNET_AUTO_CROSS_ENABLE              1\r
92 #endif\r
93 \r
94 #if( ipconfigETHERNET_AN_ENABLE == 0 )\r
95         /*\r
96          * The following three defines are only used in case there\r
97          * is no auto-negotiation.\r
98          */\r
99         #if !defined( ipconfigETHERNET_CROSSED_LINK )\r
100                 #define ipconfigETHERNET_CROSSED_LINK                   1\r
101         #endif\r
102 \r
103         #if !defined( ipconfigETHERNET_USE_100MB )\r
104                 #define ipconfigETHERNET_USE_100MB                              1\r
105         #endif\r
106 \r
107         #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )\r
108                 #define ipconfigETHERNET_USE_FULL_DUPLEX                1\r
109         #endif\r
110 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */\r
111 \r
112 /* Default the size of the stack used by the EMAC deferred handler task to twice\r
113 the size of the stack used by the idle task - but allow this to be overridden in\r
114 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */\r
115 #ifndef configEMAC_TASK_STACK_SIZE\r
116         #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )\r
117 #endif\r
118 \r
119 /* Two choices must be made: RMII versus MII,\r
120 and the index of the PHY in use ( between 0 and 31 ). */\r
121 #ifndef ipconfigUSE_RMII\r
122         #ifdef STM32F7xx\r
123                 #define ipconfigUSE_RMII        1\r
124         #else\r
125                 #define ipconfigUSE_RMII        0\r
126         #endif /* STM32F7xx */\r
127 #endif /* ipconfigUSE_RMII */\r
128 \r
129 #ifndef ipconfigPHY_INDEX\r
130         #ifdef STM32F7xx\r
131                 #define ipconfigPHY_INDEX       0\r
132         #else\r
133                 #define ipconfigPHY_INDEX       1\r
134         #endif /* STM32F7xx */\r
135 #endif /* ipconfigPHY_INDEX */\r
136 \r
137 \r
138 /*-----------------------------------------------------------*/\r
139 \r
140 /*\r
141  * A deferred interrupt handler task that processes\r
142  */\r
143 static void prvEMACHandlerTask( void *pvParameters );\r
144 \r
145 /*\r
146  * Force a negotiation with the Switch or Router and wait for LS.\r
147  */\r
148 static void prvEthernetUpdateConfig( BaseType_t xForce );\r
149 \r
150 /*\r
151  * See if there is a new packet and forward it to the IP-task.\r
152  */\r
153 static BaseType_t prvNetworkInterfaceInput( void );\r
154 \r
155 #if( ipconfigUSE_LLMNR != 0 )\r
156         /*\r
157          * For LLMNR, an extra MAC-address must be configured to\r
158          * be able to receive the multicast messages.\r
159          */\r
160         static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);\r
161 #endif\r
162 \r
163 /*\r
164  * Check if a given packet should be accepted.\r
165  */\r
166 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );\r
167 \r
168 /*\r
169  * Initialise the TX descriptors.\r
170  */\r
171 static void prvDMATxDescListInit( void );\r
172 \r
173 /*\r
174  * Initialise the RX descriptors.\r
175  */\r
176 static void prvDMARxDescListInit( void );\r
177 \r
178 /* After packets have been sent, the network\r
179 buffers will be released. */\r
180 static void vClearTXBuffers( void );\r
181 \r
182 /*-----------------------------------------------------------*/\r
183 \r
184 /* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
185 the Rx interrupt is handled, although code is included for other events to\r
186 enable future expansion. */\r
187 static volatile uint32_t ulISREvents;\r
188 \r
189 #if( ipconfigUSE_LLMNR == 1 )\r
190         static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };\r
191 #endif\r
192 \r
193 static EthernetPhy_t xPhyObject;\r
194 \r
195 /* Ethernet handle. */\r
196 static ETH_HandleTypeDef xETH;\r
197 \r
198 /* xTXDescriptorSemaphore is a counting semaphore with\r
199 a maximum count of ETH_TXBUFNB, which is the number of\r
200 DMA TX descriptors. */\r
201 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
202 \r
203 /*\r
204  * Note: it is adviced to define both\r
205  *\r
206  *     #define  ipconfigZERO_COPY_RX_DRIVER   1\r
207  *     #define  ipconfigZERO_COPY_TX_DRIVER   1\r
208  *\r
209  * The method using memcpy is slower and probaly uses more RAM memory.\r
210  * The possibility is left in the code just for comparison.\r
211  *\r
212  * It is adviced to define ETH_TXBUFNB at least 4. Note that no\r
213  * TX buffers are allocated in a zero-copy driver.\r
214  */\r
215 /* MAC buffers: ---------------------------------------------------------*/\r
216 \r
217 /* Put the DMA descriptors in '.first_data'.\r
218 This is important for STM32F7, which has an L1 data cache.\r
219 The first 64KB of the SRAM is not cached. */\r
220 \r
221 /* Ethernet Rx MA Descriptor */\r
222 __attribute__ ((aligned (32)))\r
223 __attribute__ ((section(".first_data")))\r
224         ETH_DMADescTypeDef  DMARxDscrTab[ ETH_RXBUFNB ];\r
225 \r
226 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )\r
227         /* Ethernet Receive Buffer */\r
228         __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END;\r
229 #endif\r
230 \r
231 /* Ethernet Tx DMA Descriptor */\r
232 __attribute__ ((aligned (32)))\r
233 __attribute__ ((section(".first_data")))\r
234         ETH_DMADescTypeDef  DMATxDscrTab[ ETH_TXBUFNB ];\r
235 \r
236 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
237         /* Ethernet Transmit Buffer */\r
238         __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END;\r
239 #endif\r
240 \r
241 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
242         /* DMATxDescToClear points to the next TX DMA descriptor\r
243         that must be cleared by vClearTXBuffers(). */\r
244         static __IO ETH_DMADescTypeDef  *DMATxDescToClear;\r
245 #endif\r
246 \r
247 /* ucMACAddress as it appears in main.c */\r
248 extern const uint8_t ucMACAddress[ 6 ];\r
249 \r
250 /* Holds the handle of the task used as a deferred interrupt processor.  The\r
251 handle is used so direct notifications can be sent to the task for all EMAC/DMA\r
252 related interrupts. */\r
253 static TaskHandle_t xEMACTaskHandle = NULL;\r
254 \r
255 /* For local use only: describe the PHY's properties: */\r
256 const PhyProperties_t xPHYProperties =\r
257 {\r
258         #if( ipconfigETHERNET_AN_ENABLE != 0 )\r
259                 .ucSpeed = PHY_SPEED_AUTO,\r
260                 .ucDuplex = PHY_DUPLEX_AUTO,\r
261         #else\r
262                 #if( ipconfigETHERNET_USE_100MB != 0 )\r
263                         .ucSpeed = PHY_SPEED_100,\r
264                 #else\r
265                         .ucSpeed = PHY_SPEED_10,\r
266                 #endif\r
267 \r
268                 #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )\r
269                         .duplex = PHY_DUPLEX_FULL,\r
270                 #else\r
271                         .duplex = PHY_DUPLEX_HALF,\r
272                 #endif\r
273         #endif\r
274 \r
275         #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )\r
276                 .ucMDI_X = PHY_MDIX_AUTO,\r
277         #elif( ipconfigETHERNET_CROSSED_LINK != 0 )\r
278                 .ucMDI_X = PHY_MDIX_CROSSED,\r
279         #else\r
280                 .ucMDI_X = PHY_MDIX_DIRECT,\r
281         #endif\r
282 };\r
283 \r
284 /*-----------------------------------------------------------*/\r
285 \r
286 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )\r
287 {\r
288 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
289 \r
290         /* Ethernet RX-Complete callback function, elsewhere declared as weak. */\r
291     ulISREvents |= EMAC_IF_RX_EVENT;\r
292         /* Wakeup the prvEMACHandlerTask. */\r
293         if( xEMACTaskHandle != NULL )\r
294         {\r
295                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
296                 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
297         }\r
298 }\r
299 /*-----------------------------------------------------------*/\r
300 \r
301 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )\r
302 {\r
303 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
304 \r
305         /* This call-back is only useful in case packets are being sent\r
306         zero-copy.  Once they're sent, the buffers will be released\r
307         by the function vClearTXBuffers(). */\r
308         ulISREvents |= EMAC_IF_TX_EVENT;\r
309         /* Wakeup the prvEMACHandlerTask. */\r
310         if( xEMACTaskHandle != NULL )\r
311         {\r
312                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
313                 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
314         }\r
315 \r
316 }\r
317 /*-----------------------------------------------------------*/\r
318 \r
319 static void vClearTXBuffers()\r
320 {\r
321 __IO ETH_DMADescTypeDef  *txLastDescriptor = xETH.TxDesc;\r
322 size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
323 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
324         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
325         uint8_t *ucPayLoad;\r
326 #endif\r
327 \r
328         /* This function is called after a TX-completion interrupt.\r
329         It will release each Network Buffer used in xNetworkInterfaceOutput().\r
330         'uxCount' represents the number of descriptors given to DMA for transmission.\r
331         After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */\r
332         while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )\r
333         {\r
334                 if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )\r
335                 {\r
336                         break;\r
337                 }\r
338                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
339                 {\r
340                         ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;\r
341 \r
342                         if( ucPayLoad != NULL )\r
343                         {\r
344                                 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );\r
345                                 if( pxNetworkBuffer != NULL )\r
346                                 {\r
347                                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;\r
348                                 }\r
349                                 DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;\r
350                         }\r
351                 }\r
352                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
353 \r
354                 DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );\r
355 \r
356                 uxCount--;\r
357                 /* Tell the counting semaphore that one more TX descriptor is available. */\r
358                 xSemaphoreGive( xTXDescriptorSemaphore );\r
359         }\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 BaseType_t xNetworkInterfaceInitialise( void )\r
364 {\r
365 HAL_StatusTypeDef hal_eth_init_status;\r
366 BaseType_t xResult;\r
367 \r
368         if( xEMACTaskHandle == NULL )\r
369         {\r
370                 if( xTXDescriptorSemaphore == NULL )\r
371                 {\r
372                         xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );\r
373                         configASSERT( xTXDescriptorSemaphore );\r
374                 }\r
375 \r
376                 /* Initialise ETH */\r
377 \r
378                 xETH.Instance = ETH;\r
379 //#warning Enable auto-nego again\r
380                 xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;\r
381 //              xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;\r
382                 xETH.Init.Speed = ETH_SPEED_100M;\r
383                 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;\r
384                 xETH.Init.PhyAddress = ipconfigPHY_INDEX;\r
385 \r
386                 xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;\r
387                 xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;\r
388 \r
389                 /* using the ETH_CHECKSUM_BY_HARDWARE option:\r
390                 both the IP and the protocol checksums will be calculated\r
391                 by the peripheral. */\r
392                 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;\r
393 \r
394                 #if( ipconfigUSE_RMII != 0 )\r
395                 {\r
396                         xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;\r
397                 }\r
398                 #else\r
399                 {\r
400                         xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;\r
401                 }\r
402                 #endif /* ipconfigUSE_RMII */\r
403 \r
404                 hal_eth_init_status = HAL_ETH_Init( &xETH );\r
405 \r
406                 /* Only for inspection by debugger. */\r
407                 ( void ) hal_eth_init_status;\r
408 \r
409                 /* Set the TxDesc and RxDesc pointers. */\r
410                 xETH.TxDesc = DMATxDscrTab;\r
411                 xETH.RxDesc = DMARxDscrTab;\r
412 \r
413                 /* Make sure that all unused fields are cleared. */\r
414                 memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );\r
415                 memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );\r
416 \r
417                 /* Initialize Tx Descriptors list: Chain Mode */\r
418                 DMATxDescToClear = DMATxDscrTab;\r
419 \r
420                 /* Initialise TX-descriptors. */\r
421                 prvDMATxDescListInit();\r
422 \r
423                 /* Initialise RX-descriptors. */\r
424                 prvDMARxDescListInit();\r
425 \r
426                 #if( ipconfigUSE_LLMNR != 0 )\r
427                 {\r
428                         /* Program the LLMNR address at index 1. */\r
429                         prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );\r
430                 }\r
431                 #endif\r
432 \r
433                 /* Force a negotiation with the Switch or Router and wait for LS. */\r
434                 prvEthernetUpdateConfig( pdTRUE );\r
435 \r
436                 /* The deferred interrupt handler task is created at the highest\r
437                 possible priority to ensure the interrupt handler can return directly\r
438                 to it.  The task's handle is stored in xEMACTaskHandle so interrupts can\r
439                 notify the task when there is something to process. */\r
440                 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );\r
441         } /* if( xEMACTaskHandle == NULL ) */\r
442 \r
443         if( xPhyObject.ulLinkStatusMask != 0 )\r
444         {\r
445                 xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;\r
446                 xResult = pdPASS;\r
447                 FreeRTOS_printf( ( "Link Status is high\n" ) ) ;\r
448         }\r
449         else\r
450         {\r
451                 /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running\r
452                 and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */\r
453                 xResult = pdFAIL;\r
454                 FreeRTOS_printf( ( "Link Status still low\n" ) ) ;\r
455         }\r
456         /* When returning non-zero, the stack will become active and\r
457     start DHCP (in configured) */\r
458         return xResult;\r
459 }\r
460 /*-----------------------------------------------------------*/\r
461 \r
462 static void prvDMATxDescListInit()\r
463 {\r
464 ETH_DMADescTypeDef *pxDMADescriptor;\r
465 BaseType_t xIndex;\r
466 \r
467         /* Get the pointer on the first member of the descriptor list */\r
468         pxDMADescriptor = DMATxDscrTab;\r
469 \r
470         /* Fill each DMA descriptor with the right values */\r
471         for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )\r
472         {\r
473                 /* Set Second Address Chained bit */\r
474                 pxDMADescriptor->Status = ETH_DMATXDESC_TCH;\r
475 \r
476                 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
477                 {\r
478                         /* Set Buffer1 address pointer */\r
479                         pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );\r
480                 }\r
481                 #endif\r
482 \r
483                 if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )\r
484                 {\r
485                         /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */\r
486                         pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;\r
487                 }\r
488 \r
489                 /* Initialize the next descriptor with the Next Descriptor Polling Enable */\r
490                 if( xIndex < ETH_TXBUFNB - 1 )\r
491                 {\r
492                         /* Set next descriptor address register with next descriptor base address */\r
493                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );\r
494                 }\r
495                 else\r
496                 {\r
497                         /* For last descriptor, set next descriptor address register equal to the first descriptor base address */\r
498                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;\r
499                 }\r
500         }\r
501 \r
502         /* Set Transmit Descriptor List Address Register */\r
503         xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;\r
504 }\r
505 /*-----------------------------------------------------------*/\r
506 \r
507 static void prvDMARxDescListInit()\r
508 {\r
509 ETH_DMADescTypeDef *pxDMADescriptor;\r
510 BaseType_t xIndex;\r
511         /*\r
512          * RX-descriptors.\r
513          */\r
514 \r
515         /* Get the pointer on the first member of the descriptor list */\r
516         pxDMADescriptor = DMARxDscrTab;\r
517 \r
518         /* Fill each DMA descriptor with the right values */\r
519         for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )\r
520         {\r
521 \r
522                 /* Set Buffer1 size and Second Address Chained bit */\r
523                 pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;  \r
524 \r
525                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
526                 {\r
527                 /* Set Buffer1 address pointer */\r
528                 NetworkBufferDescriptor_t *pxBuffer;\r
529 \r
530                         pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );\r
531                         /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'\r
532                         Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */\r
533                         configASSERT( pxBuffer != NULL );\r
534                         if( pxBuffer != NULL )\r
535                         {\r
536                                 pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;\r
537                                 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;\r
538                         }\r
539                 }\r
540                 #else\r
541                 {\r
542                         /* Set Buffer1 address pointer */\r
543                         pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );\r
544                         /* Set Own bit of the Rx descriptor Status */\r
545                         pxDMADescriptor->Status = ETH_DMARXDESC_OWN;\r
546                 }\r
547                 #endif\r
548 \r
549                 /* Initialize the next descriptor with the Next Descriptor Polling Enable */\r
550                 if( xIndex < ETH_RXBUFNB - 1 )\r
551                 {\r
552                         /* Set next descriptor address register with next descriptor base address */\r
553                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );\r
554                 }\r
555                 else\r
556                 {\r
557                         /* For last descriptor, set next descriptor address register equal to the first descriptor base address */\r
558                         pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;\r
559                 }\r
560 \r
561         }\r
562         /* Set Receive Descriptor List Address Register */\r
563         xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;\r
564 }\r
565 /*-----------------------------------------------------------*/\r
566 \r
567 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)\r
568 {\r
569 uint32_t ulTempReg;\r
570 \r
571         /* Calculate the selected MAC address high register. */\r
572         ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];\r
573 \r
574         /* Load the selected MAC address high register. */\r
575         ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;\r
576 \r
577         /* Calculate the selected MAC address low register. */\r
578         ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];\r
579 \r
580         /* Load the selected MAC address low register */\r
581         ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;\r
582 }\r
583 /*-----------------------------------------------------------*/\r
584 \r
585 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
586 {\r
587 BaseType_t xReturn = pdFAIL;\r
588 uint32_t ulTransmitSize = 0;\r
589 __IO ETH_DMADescTypeDef *pxDmaTxDesc;\r
590 /* Do not wait too long for a free TX DMA buffer. */\r
591 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );\r
592 \r
593         #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
594         {\r
595         ProtocolPacket_t *pxPacket;\r
596 \r
597                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
598                 {\r
599                         configASSERT( bReleaseAfterSend != 0 );\r
600                 }\r
601                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
602 \r
603                 /* If the peripheral must calculate the checksum, it wants\r
604                 the protocol checksum to have a value of zero. */\r
605                 pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );\r
606 \r
607                 if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )\r
608                 {\r
609                         pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;\r
610                 }\r
611         }\r
612         #endif\r
613 \r
614         /* Open a do {} while ( 0 ) loop to be able to call break. */\r
615         do\r
616         {\r
617                 if( xPhyObject.ulLinkStatusMask != 0 )\r
618                 {\r
619                         if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
620                         {\r
621                                 /* Time-out waiting for a free TX descriptor. */\r
622                                 break;\r
623                         }\r
624 \r
625                         /* This function does the actual transmission of the packet. The packet is\r
626                         contained in 'pxDescriptor' that is passed to the function. */\r
627                         pxDmaTxDesc = xETH.TxDesc;\r
628 \r
629                         /* Is this buffer available? */\r
630                         configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );\r
631 \r
632                         {\r
633                                 /* Is this buffer available? */\r
634                                 /* Get bytes in current buffer. */\r
635                                 ulTransmitSize = pxDescriptor->xDataLength;\r
636 \r
637                                 if( ulTransmitSize > ETH_TX_BUF_SIZE )\r
638                                 {\r
639                                         ulTransmitSize = ETH_TX_BUF_SIZE;\r
640                                 }\r
641 \r
642                                 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
643                                 {\r
644                                         /* Copy the bytes. */\r
645                                         memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );\r
646                                 }\r
647                                 #else\r
648                                 {\r
649                                         /* Move the buffer. */\r
650                                         pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;\r
651                                         /* The Network Buffer has been passed to DMA, no need to release it. */\r
652                                         bReleaseAfterSend = pdFALSE_UNSIGNED;\r
653                                 }\r
654                                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
655 \r
656                                 /* Ask to set the IPv4 checksum.\r
657                                 Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */\r
658                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;\r
659 \r
660                                 /* Prepare transmit descriptors to give to DMA. */\r
661 \r
662                                 /* Set LAST and FIRST segment */\r
663                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;\r
664                                 /* Set frame size */\r
665                                 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );\r
666                                 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */\r
667                                 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;\r
668 \r
669                                 /* Point to next descriptor */\r
670                                 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );\r
671                                 /* Ensure completion of memory access */\r
672                                 __DSB();\r
673                                 /* Resume DMA transmission*/\r
674                                 xETH.Instance->DMATPDR = 0;\r
675                                 iptraceNETWORK_INTERFACE_TRANSMIT();\r
676                                 xReturn = pdPASS;\r
677                         }\r
678                 }\r
679                 else\r
680                 {\r
681                         /* The PHY has no Link Status, packet shall be dropped. */\r
682                 }\r
683         } while( 0 );\r
684         /* The buffer has been sent so can be released. */\r
685         if( bReleaseAfterSend != pdFALSE )\r
686         {\r
687                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
688         }\r
689 \r
690         return xReturn;\r
691 }\r
692 /*-----------------------------------------------------------*/\r
693 \r
694 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )\r
695 {\r
696 const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;\r
697 \r
698         switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )\r
699         {\r
700         case ipARP_FRAME_TYPE:\r
701                 /* Check it later. */\r
702                 return pdTRUE;\r
703         case ipIPv4_FRAME_TYPE:\r
704                 /* Check it here. */\r
705                 break;\r
706         default:\r
707                 /* Refuse the packet. */\r
708                 return pdFALSE;\r
709         }\r
710 \r
711         #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )\r
712         {\r
713                 const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);\r
714                 uint32_t ulDestinationIPAddress;\r
715 \r
716                 /* Ensure that the incoming packet is not fragmented (only outgoing packets\r
717                  * can be fragmented) as these are the only handled IP frames currently. */\r
718                 if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )\r
719                 {\r
720                         return pdFALSE;\r
721                 }\r
722                 /* HT: Might want to make the following configurable because\r
723                  * most IP messages have a standard length of 20 bytes */\r
724 \r
725                 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes\r
726                  * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */\r
727                 if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )\r
728                 {\r
729                         return pdFALSE;\r
730                 }\r
731 \r
732                 ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;\r
733                 /* Is the packet for this node? */\r
734                 if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&\r
735                         /* Is it a broadcast address x.x.x.255 ? */\r
736                         ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&\r
737                 #if( ipconfigUSE_LLMNR == 1 )\r
738                         ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&\r
739                 #endif\r
740                         ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {\r
741                         FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );\r
742                         return pdFALSE;\r
743                 }\r
744 \r
745                 if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )\r
746                 {\r
747                         uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;\r
748 \r
749                         if( ( xPortHasUDPSocket( port ) == pdFALSE )\r
750                         #if ipconfigUSE_LLMNR == 1\r
751                                 && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )\r
752                         #endif\r
753                         #if ipconfigUSE_NBNS == 1\r
754                                 && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )\r
755                         #endif\r
756                         #if ipconfigUSE_DNS == 1\r
757                                 && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )\r
758                         #endif\r
759                                 ) {\r
760                                 /* Drop this packet, not for this device. */\r
761                                 return pdFALSE;\r
762                         }\r
763                 }\r
764         }\r
765         #endif  /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */\r
766         return pdTRUE;\r
767 }\r
768 /*-----------------------------------------------------------*/\r
769 \r
770 static BaseType_t prvNetworkInterfaceInput( void )\r
771 {\r
772 NetworkBufferDescriptor_t *pxCurDescriptor;\r
773 NetworkBufferDescriptor_t *pxNewDescriptor = NULL;\r
774 BaseType_t xReceivedLength, xAccepted;\r
775 __IO ETH_DMADescTypeDef *pxDMARxDescriptor;\r
776 xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
777 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );\r
778 uint8_t *pucBuffer;\r
779 \r
780         pxDMARxDescriptor = xETH.RxDesc;\r
781 \r
782         if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 )\r
783         {\r
784                 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */\r
785                 xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;\r
786 \r
787                 pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;\r
788 \r
789                 /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */\r
790                 /* Chained Mode */    \r
791                 /* Selects the next DMA Rx descriptor list for next buffer to read */ \r
792                 xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;\r
793         }\r
794         else\r
795         {\r
796                 xReceivedLength = 0;\r
797         }\r
798 \r
799         /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */\r
800 \r
801         /* get received frame */\r
802         if( xReceivedLength > 0ul )\r
803         {\r
804                 /* In order to make the code easier and faster, only packets in a single buffer\r
805                 will be accepted.  This can be done by making the buffers large enough to\r
806                 hold a complete Ethernet packet (1536 bytes).\r
807                 Therefore, two sanity checks: */\r
808                 configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );\r
809 \r
810                 if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )\r
811                 {\r
812                         /* Not an Ethernet frame-type or a checmsum error. */\r
813                         xAccepted = pdFALSE;\r
814                 }\r
815                 else\r
816                 {\r
817                         /* See if this packet must be handled. */\r
818                         xAccepted = xMayAcceptPacket( pucBuffer );\r
819                 }\r
820 \r
821                 if( xAccepted != pdFALSE )\r
822                 {\r
823                         /* The packet wil be accepted, but check first if a new Network Buffer can\r
824                         be obtained. If not, the packet will still be dropped. */\r
825                         pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );\r
826 \r
827                         if( pxNewDescriptor == NULL )\r
828                         {\r
829                                 /* A new descriptor can not be allocated now. This packet will be dropped. */\r
830                                 xAccepted = pdFALSE;\r
831                         }\r
832                 }\r
833                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
834                 {\r
835                         /* Find out which Network Buffer was originally passed to the descriptor. */\r
836                         pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
837                         configASSERT( pxCurDescriptor != NULL );\r
838                 }\r
839                 #else\r
840                 {\r
841                         /* In this mode, the two descriptors are the same. */\r
842                         pxCurDescriptor = pxNewDescriptor;\r
843                         if( pxNewDescriptor != NULL )\r
844                         {\r
845                                 /* The packet is acepted and a new Network Buffer was created,\r
846                                 copy data to the Network Bufffer. */\r
847                                 memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );\r
848                         }\r
849                 }\r
850                 #endif\r
851 \r
852                 if( xAccepted != pdFALSE )\r
853                 {\r
854                         pxCurDescriptor->xDataLength = xReceivedLength;\r
855                         xRxEvent.pvData = ( void * ) pxCurDescriptor;\r
856 \r
857                         /* Pass the data to the TCP/IP task for processing. */\r
858                         if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )\r
859                         {\r
860                                 /* Could not send the descriptor into the TCP/IP stack, it\r
861                                 must be released. */\r
862                                 vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );\r
863                                 iptraceETHERNET_RX_EVENT_LOST();\r
864                         }\r
865                         else\r
866                         {\r
867                                 iptraceNETWORK_INTERFACE_RECEIVE();\r
868                         }\r
869                 }\r
870 \r
871                 /* Release descriptors to DMA */\r
872                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
873                 {\r
874                         /* Set Buffer1 address pointer */\r
875                         if( pxNewDescriptor != NULL )\r
876                         {\r
877                                 pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;\r
878                         }\r
879                         else\r
880                         {\r
881                                 /* The packet was dropped and the same Network\r
882                                 Buffer will be used to receive a new packet. */\r
883                         }\r
884                 }\r
885                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
886 \r
887                 /* Set Buffer1 size and Second Address Chained bit */\r
888                 pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;  \r
889                 pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;\r
890 \r
891                 /* Ensure completion of memory access */\r
892                 __DSB();\r
893                 /* When Rx Buffer unavailable flag is set clear it and resume\r
894                 reception. */\r
895                 if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )\r
896                 {\r
897                         /* Clear RBUS ETHERNET DMA flag. */\r
898                         xETH.Instance->DMASR = ETH_DMASR_RBUS;\r
899 \r
900                         /* Resume DMA reception. */\r
901                         xETH.Instance->DMARPDR = 0;\r
902                 }\r
903         }\r
904 \r
905         return ( xReceivedLength > 0 );\r
906 }\r
907 /*-----------------------------------------------------------*/\r
908 \r
909 \r
910 BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue )\r
911 {\r
912 uint16_t usPrevAddress = xETH.Init.PhyAddress;\r
913 BaseType_t xResult;\r
914 HAL_StatusTypeDef xHALResult;\r
915 \r
916         xETH.Init.PhyAddress = xAddress;\r
917         xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue );\r
918         xETH.Init.PhyAddress = usPrevAddress;\r
919 \r
920         if( xHALResult == HAL_OK )\r
921         {\r
922                 xResult = 0;\r
923         }\r
924         else\r
925         {\r
926                 xResult = -1;\r
927         }\r
928         return xResult;\r
929 }\r
930 /*-----------------------------------------------------------*/\r
931 \r
932 BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue )\r
933 {\r
934 uint16_t usPrevAddress = xETH.Init.PhyAddress;\r
935 BaseType_t xResult;\r
936 HAL_StatusTypeDef xHALResult;\r
937 \r
938         xETH.Init.PhyAddress = xAddress;\r
939         xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue );\r
940         xETH.Init.PhyAddress = usPrevAddress;\r
941 \r
942         if( xHALResult == HAL_OK )\r
943         {\r
944                 xResult = 0;\r
945         }\r
946         else\r
947         {\r
948                 xResult = -1;\r
949         }\r
950         return xResult;\r
951 }\r
952 /*-----------------------------------------------------------*/\r
953 \r
954 void phy_test()\r
955 {\r
956 BaseType_t xPhyCount;\r
957 BaseType_t xPhyIndex;\r
958 \r
959         vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );\r
960         xPhyCount = xPhyDiscover( &xPhyObject );\r
961         FreeRTOS_printf( ( "PHY count %ld\n", xPhyCount ) );\r
962         for( xPhyIndex = 0; xPhyIndex < xPhyCount; xPhyIndex++ )\r
963         {\r
964                 FreeRTOS_printf( ( "PHY[%d] at address %d ( 0x%08X )\n",\r
965                         xPhyIndex,\r
966                         xPhyObject.ucPhyIndexes[ xPhyIndex ],\r
967                         xPhyObject.ulPhyIDs[ xPhyIndex ] ) );\r
968 \r
969         }\r
970         \r
971 }\r
972 \r
973 void vMACBProbePhy( void )\r
974 {\r
975         vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );\r
976         xPhyDiscover( &xPhyObject );\r
977         xPhyConfigure( &xPhyObject, &xPHYProperties );\r
978 }\r
979 /*-----------------------------------------------------------*/\r
980 \r
981 static void prvEthernetUpdateConfig( BaseType_t xForce )\r
982 {\r
983         FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02X Force %d\n",\r
984                 xPhyObject.ulLinkStatusMask,\r
985                 ( int )xForce ) );\r
986 \r
987         if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )\r
988         {\r
989                 /* Restart the auto-negotiation. */\r
990                 if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )\r
991                 {\r
992                         xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );\r
993 \r
994                         /* Configure the MAC with the Duplex Mode fixed by the\r
995                         auto-negotiation process. */\r
996                         if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )\r
997                         {\r
998                                 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;\r
999                         }\r
1000                         else\r
1001                         {\r
1002                                 xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;\r
1003                         }\r
1004 \r
1005                         /* Configure the MAC with the speed fixed by the\r
1006                         auto-negotiation process. */\r
1007                         if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )\r
1008                         {\r
1009                                 xETH.Init.Speed = ETH_SPEED_10M;\r
1010                         }\r
1011                         else\r
1012                         {\r
1013                                 xETH.Init.Speed = ETH_SPEED_100M;\r
1014                         }\r
1015                 }\r
1016                 else /* AutoNegotiation Disable */\r
1017                 {\r
1018                         /* Check parameters */\r
1019                         assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );\r
1020                         assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );\r
1021 \r
1022                         if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX )\r
1023                         {\r
1024                                 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;\r
1025                         }\r
1026                         else\r
1027                         {\r
1028                                 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;\r
1029                         }\r
1030 \r
1031                         if( xETH.Init.Speed == ETH_SPEED_10M )\r
1032                         {\r
1033                                 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;\r
1034                         }\r
1035                         else\r
1036                         {\r
1037                                 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;\r
1038                         }\r
1039 \r
1040                         xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;\r
1041 \r
1042                         /* Use predefined (fixed) configuration. */\r
1043                         xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );\r
1044                 }\r
1045 \r
1046                 /* ETHERNET MAC Re-Configuration */\r
1047                 HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);\r
1048 \r
1049                 /* Restart MAC interface */\r
1050                 HAL_ETH_Start( &xETH);\r
1051         }\r
1052         else\r
1053         {\r
1054                 /* Stop MAC interface */\r
1055                 HAL_ETH_Stop( &xETH );\r
1056         }\r
1057 }\r
1058 /*-----------------------------------------------------------*/\r
1059 \r
1060 BaseType_t xGetPhyLinkStatus( void )\r
1061 {\r
1062 BaseType_t xReturn;\r
1063 \r
1064         if( xPhyObject.ulLinkStatusMask != 0 )\r
1065         {\r
1066                 xReturn = pdPASS;\r
1067         }\r
1068         else\r
1069         {\r
1070                 xReturn = pdFAIL;\r
1071         }\r
1072 \r
1073         return xReturn;\r
1074 }\r
1075 /*-----------------------------------------------------------*/\r
1076 \r
1077 #define niBUFFER_1_PACKET_SIZE          1536\r
1078 \r
1079 static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );\r
1080 \r
1081 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )\r
1082 {\r
1083 \r
1084 uint8_t *ucRAMBuffer = ucNetworkPackets;\r
1085 uint32_t ul;\r
1086 \r
1087         for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )\r
1088         {\r
1089                 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;\r
1090                 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );\r
1091                 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;\r
1092         }\r
1093 }\r
1094 /*-----------------------------------------------------------*/\r
1095 \r
1096 static void prvEMACHandlerTask( void *pvParameters )\r
1097 {\r
1098 UBaseType_t uxLastMinBufferCount = 0;\r
1099 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1100 UBaseType_t uxLastMinQueueSpace = 0;\r
1101 #endif\r
1102 UBaseType_t uxCurrentCount;\r
1103 BaseType_t xResult;\r
1104 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );\r
1105 \r
1106         /* Remove compiler warnings about unused parameters. */\r
1107         ( void ) pvParameters;\r
1108 \r
1109         for( ;; )\r
1110         {\r
1111                 xResult = 0;\r
1112                 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
1113                 if( uxLastMinBufferCount != uxCurrentCount )\r
1114                 {\r
1115                         /* The logging produced below may be helpful\r
1116                         while tuning +TCP: see how many buffers are in use. */\r
1117                         uxLastMinBufferCount = uxCurrentCount;\r
1118                         FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
1119                                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
1120                 }\r
1121 \r
1122                 if( xTXDescriptorSemaphore != NULL )\r
1123                 {\r
1124                 static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;\r
1125 \r
1126                         uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
1127                         if( uxLowestSemCount > uxCurrentCount )\r
1128                         {\r
1129                                 uxLowestSemCount = uxCurrentCount;\r
1130                                 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );\r
1131                         }\r
1132 \r
1133                 }\r
1134 \r
1135                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1136                 {\r
1137                         uxCurrentCount = uxGetMinimumIPQueueSpace();\r
1138                         if( uxLastMinQueueSpace != uxCurrentCount )\r
1139                         {\r
1140                                 /* The logging produced below may be helpful\r
1141                                 while tuning +TCP: see how many buffers are in use. */\r
1142                                 uxLastMinQueueSpace = uxCurrentCount;\r
1143                                 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
1144                         }\r
1145                 }\r
1146                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
1147 \r
1148                 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )\r
1149                 {\r
1150                         /* No events to process now, wait for the next. */\r
1151                         ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );\r
1152                 }\r
1153 \r
1154                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
1155                 {\r
1156                         ulISREvents &= ~EMAC_IF_RX_EVENT;\r
1157 \r
1158                         xResult = prvNetworkInterfaceInput();\r
1159                         if( xResult > 0 )\r
1160                         {\r
1161                                 while( prvNetworkInterfaceInput() > 0 )\r
1162                                 {\r
1163                                 }\r
1164                         }\r
1165                 }\r
1166 \r
1167                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
1168                 {\r
1169                         /* Code to release TX buffers if zero-copy is used. */\r
1170                         ulISREvents &= ~EMAC_IF_TX_EVENT;\r
1171                         /* Check if DMA packets have been delivered. */\r
1172                         vClearTXBuffers();\r
1173                 }\r
1174 \r
1175                 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )\r
1176                 {\r
1177                         /* Future extension: logging about errors that occurred. */\r
1178                         ulISREvents &= ~EMAC_IF_ERR_EVENT;\r
1179                 }\r
1180                 if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )\r
1181                 {\r
1182                         /* Something has changed to a Link Status, need re-check. */\r
1183                         prvEthernetUpdateConfig( pdFALSE );\r
1184                 }\r
1185         }\r
1186 }\r
1187 /*-----------------------------------------------------------*/\r
1188 \r
1189 void ETH_IRQHandler( void )\r
1190 {\r
1191         HAL_ETH_IRQHandler( &xETH );\r
1192 }\r
1193 \r