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