2 * Some constants, hardware definitions and comments taken from ST's HAL driver
3 * library, COPYRIGHT(c) 2015 STMicroelectronics.
8 Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
10 Permission is hereby granted, free of charge, to any person obtaining a copy of
11 this software and associated documentation files (the "Software"), to deal in
12 the Software without restriction, including without limitation the rights to
13 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14 the Software, and to permit persons to whom the Software is furnished to do so,
15 subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in all
18 copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 http://aws.amazon.com/freertos
28 http://www.FreeRTOS.org
31 /* Standard includes. */
36 /* FreeRTOS includes. */
42 /* FreeRTOS+TCP includes. */
43 #include "FreeRTOS_IP.h"
44 #include "FreeRTOS_Sockets.h"
45 #include "FreeRTOS_IP_Private.h"
46 #include "FreeRTOS_DNS.h"
47 #include "NetworkBufferManagement.h"
48 #include "NetworkInterface.h"
51 #include "stm32f4xx_hal.h"
53 #ifndef BMSR_LINK_STATUS
54 #define BMSR_LINK_STATUS 0x0004UL
57 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
58 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
60 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
63 #ifndef PHY_LS_LOW_CHECK_TIME_MS
64 /* Check if the LinkSStatus in the PHY is still low every second. */
65 #define PHY_LS_LOW_CHECK_TIME_MS 1000
68 /* Interrupt events to process. Currently only the Rx event is processed
69 although code for other events is included to allow for possible future
71 #define EMAC_IF_RX_EVENT 1UL
72 #define EMAC_IF_TX_EVENT 2UL
73 #define EMAC_IF_ERR_EVENT 4UL
74 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
76 #define ETH_DMA_ALL_INTS \
77 ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \
78 ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \
79 ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
81 /* Naming and numbering of PHY registers. */
82 #define PHY_REG_00_BMCR 0x00 /* Basic Mode Control Register */
83 #define PHY_REG_01_BMSR 0x01 /* Basic Mode Status Register */
84 #define PHY_REG_02_PHYSID1 0x02 /* PHYS ID 1 */
85 #define PHY_REG_03_PHYSID2 0x03 /* PHYS ID 2 */
86 #define PHY_REG_04_ADVERTISE 0x04 /* Advertisement control reg */
88 #define PHY_ID_LAN8720 0x0007c0f0
89 #define PHY_ID_DP83848I 0x20005C90
91 #ifndef USE_STM324xG_EVAL
92 #define USE_STM324xG_EVAL 1
95 #if( USE_STM324xG_EVAL == 0 )
96 #define EXPECTED_PHY_ID PHY_ID_LAN8720
97 #define PHY_REG_1F_PHYSPCS 0x1F /* 31 RW PHY Special Control Status */
98 /* Use 3 bits in register 31 */
99 #define PHYSPCS_SPEED_MASK 0x0C
100 #define PHYSPCS_SPEED_10 0x04
101 #define PHYSPCS_SPEED_100 0x08
102 #define PHYSPCS_FULL_DUPLEX 0x10
104 #define EXPECTED_PHY_ID PHY_ID_DP83848I
106 #define PHY_REG_10_PHY_SR 0x10 /* PHY status register Offset */
107 #define PHY_REG_19_PHYCR 0x19 /* 25 RW PHY Control Register */
110 /* Some defines used internally here to indicate preferences about speed, MDIX
111 (wired direct or crossed), and duplex (half or full). */
112 #define PHY_SPEED_10 1
113 #define PHY_SPEED_100 2
114 #define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100)
116 #define PHY_MDIX_DIRECT 1
117 #define PHY_MDIX_CROSSED 2
118 #define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT)
120 #define PHY_DUPLEX_HALF 1
121 #define PHY_DUPLEX_FULL 2
122 #define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF)
124 #define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
127 * Description of all capabilities that can be advertised to
128 * the peer (usually a switch or router).
130 #define ADVERTISE_CSMA 0x0001 /* Only selector supported. */
131 #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex. */
132 #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex. */
133 #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex. */
134 #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex. */
136 #define ADVERTISE_ALL ( ADVERTISE_10HALF | ADVERTISE_10FULL | \
137 ADVERTISE_100HALF | ADVERTISE_100FULL)
140 * Value for the 'PHY_REG_00_BMCR', the PHY's Basic Mode Control Register
142 #define BMCR_FULLDPLX 0x0100 /* Full duplex. */
143 #define BMCR_ANRESTART 0x0200 /* Auto negotiation restart. */
144 #define BMCR_ANENABLE 0x1000 /* Enable auto negotiation. */
145 #define BMCR_SPEED100 0x2000 /* Select 100Mbps. */
146 #define BMCR_RESET 0x8000 /* Reset the PHY. */
148 #define PHYCR_MDIX_EN 0x8000 /* Enable Auto MDIX. */
149 #define PHYCR_MDIX_FORCE 0x4000 /* Force MDIX crossed. */
151 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
154 * Most users will want a PHY that negotiates about
155 * the connection properties: speed, dmix and duplex.
156 * On some rare cases, you want to select what is being
157 * advertised, properties like MDIX and duplex.
160 #if !defined( ipconfigETHERNET_AN_ENABLE )
161 /* Enable auto-negotiation */
162 #define ipconfigETHERNET_AN_ENABLE 1
165 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )
166 #define ipconfigETHERNET_AUTO_CROSS_ENABLE 1
169 #if( ipconfigETHERNET_AN_ENABLE == 0 )
171 * The following three defines are only used in case there
172 * is no auto-negotiation.
174 #if !defined( ipconfigETHERNET_CROSSED_LINK )
175 #define ipconfigETHERNET_CROSSED_LINK 1
178 #if !defined( ipconfigETHERNET_USE_100MB )
179 #define ipconfigETHERNET_USE_100MB 1
182 #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
183 #define ipconfigETHERNET_USE_FULL_DUPLEX 1
185 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */
187 /* Default the size of the stack used by the EMAC deferred handler task to twice
188 the size of the stack used by the idle task - but allow this to be overridden in
189 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
190 #ifndef configEMAC_TASK_STACK_SIZE
191 #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
194 /*-----------------------------------------------------------*/
197 * A deferred interrupt handler task that processes
199 static void prvEMACHandlerTask( void *pvParameters );
202 * Force a negotiation with the Switch or Router and wait for LS.
204 static void prvEthernetUpdateConfig( BaseType_t xForce );
207 * See if there is a new packet and forward it to the IP-task.
209 static BaseType_t prvNetworkInterfaceInput( void );
211 #if( ipconfigUSE_LLMNR != 0 )
213 * For LLMNR, an extra MAC-address must be configured to
214 * be able to receive the multicast messages.
216 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);
220 * Check if a given packet should be accepted.
222 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );
225 * Initialise the TX descriptors.
227 static void prvDMATxDescListInit( void );
230 * Initialise the RX descriptors.
232 static void prvDMARxDescListInit( void );
234 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
235 /* After packets have been sent, the network
236 buffers will be released. */
237 static void vClearTXBuffers( void );
238 #endif /* ipconfigZERO_COPY_TX_DRIVER */
240 /*-----------------------------------------------------------*/
242 typedef struct _PhyProperties_t
250 /* Bit map of outstanding ETH interrupt events for processing. Currently only
251 the Rx interrupt is handled, although code is included for other events to
252 enable future expansion. */
253 static volatile uint32_t ulISREvents;
255 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
256 static uint32_t ulPHYLinkStatus = 0;
258 #if( ipconfigUSE_LLMNR == 1 )
259 static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
262 /* Ethernet handle. */
263 static ETH_HandleTypeDef xETH;
265 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
266 /* xTXDescriptorSemaphore is a counting semaphore with
267 a maximum count of ETH_TXBUFNB, which is the number of
268 DMA TX descriptors. */
269 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
270 #endif /* ipconfigZERO_COPY_TX_DRIVER */
273 * Note: it is adviced to define both
275 * #define ipconfigZERO_COPY_RX_DRIVER 1
276 * #define ipconfigZERO_COPY_TX_DRIVER 1
278 * The method using memcpy is slower and probaly uses more RAM memory.
279 * The possibility is left in the code just for comparison.
281 * It is adviced to define ETH_TXBUFNB at least 4. Note that no
282 * TX buffers are allocated in a zero-copy driver.
284 /* MAC buffers: ---------------------------------------------------------*/
285 __ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ] __ALIGN_END;/* Ethernet Rx MA Descriptor */
286 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
287 __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; /* Ethernet Receive Buffer */
290 __ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Ethernet Tx DMA Descriptor */
291 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
292 __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; /* Ethernet Transmit Buffer */
295 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
296 /* DMATxDescToClear points to the next TX DMA descriptor
297 that must be cleared by vClearTXBuffers(). */
298 static __IO ETH_DMADescTypeDef *DMATxDescToClear;
301 /* Value to be written into the 'Basic mode Control Register'. */
302 static uint32_t ulBCRvalue;
304 /* Value to be written into the 'Advertisement Control Register'. */
305 static uint32_t ulACRValue;
307 /* ucMACAddress as it appears in main.c */
308 extern const uint8_t ucMACAddress[ 6 ];
310 /* Holds the handle of the task used as a deferred interrupt processor. The
311 handle is used so direct notifications can be sent to the task for all EMAC/DMA
312 related interrupts. */
313 static TaskHandle_t xEMACTaskHandle = NULL;
315 /* For local use only: describe the PHY's properties: */
316 const PhyProperties_t xPHYProperties =
318 #if( ipconfigETHERNET_AN_ENABLE != 0 )
319 .speed = PHY_SPEED_AUTO,
320 .duplex = PHY_DUPLEX_AUTO,
322 #if( ipconfigETHERNET_USE_100MB != 0 )
323 .speed = PHY_SPEED_100,
325 .speed = PHY_SPEED_10,
328 #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
329 .duplex = PHY_DUPLEX_FULL,
331 .duplex = PHY_DUPLEX_HALF,
335 #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
336 .mdix = PHY_MDIX_AUTO,
337 #elif( ipconfigETHERNET_CROSSED_LINK != 0 )
338 .mdix = PHY_MDIX_CROSSED,
340 .mdix = PHY_MDIX_DIRECT,
344 /*-----------------------------------------------------------*/
346 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
348 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
350 /* Ethernet RX-Complete callback function, elsewhere declared as weak. */
351 ulISREvents |= EMAC_IF_RX_EVENT;
352 /* Wakeup the prvEMACHandlerTask. */
353 if( xEMACTaskHandle != NULL )
355 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
356 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
359 /*-----------------------------------------------------------*/
361 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
362 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )
364 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
366 /* This call-back is only useful in case packets are being sent
367 zero-copy. Once they're sent, the buffers will be released
368 by the function vClearTXBuffers(). */
369 ulISREvents |= EMAC_IF_TX_EVENT;
370 /* Wakeup the prvEMACHandlerTask. */
371 if( xEMACTaskHandle != NULL )
373 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
374 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
378 #endif /* ipconfigZERO_COPY_TX_DRIVER */
380 /*-----------------------------------------------------------*/
382 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
383 static void vClearTXBuffers()
385 __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc;
386 NetworkBufferDescriptor_t *pxNetworkBuffer;
388 size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
390 /* This function is called after a TX-completion interrupt.
391 It will release each Network Buffer used in xNetworkInterfaceOutput().
392 'uxCount' represents the number of descriptors given to DMA for transmission.
393 After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
394 while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )
396 if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )
401 ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
403 if( ucPayLoad != NULL )
405 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
406 if( pxNetworkBuffer != NULL )
408 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
410 DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
413 DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );
416 /* Tell the counting semaphore that one more TX descriptor is available. */
417 xSemaphoreGive( xTXDescriptorSemaphore );
420 #endif /* ipconfigZERO_COPY_TX_DRIVER */
421 /*-----------------------------------------------------------*/
423 BaseType_t xNetworkInterfaceInitialise( void )
425 HAL_StatusTypeDef hal_eth_init_status;
428 if( xEMACTaskHandle == NULL )
430 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
432 if( xTXDescriptorSemaphore == NULL )
434 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
435 configASSERT( xTXDescriptorSemaphore );
438 #endif /* ipconfigZERO_COPY_TX_DRIVER */
443 xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
444 xETH.Init.Speed = ETH_SPEED_100M;
445 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
446 xETH.Init.PhyAddress = 1;
448 xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;
449 xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
451 /* using the ETH_CHECKSUM_BY_HARDWARE option:
452 both the IP and the protocol checksums will be calculated
453 by the peripheral. */
454 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
456 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
457 hal_eth_init_status = HAL_ETH_Init( &xETH );
459 /* Only for inspection by debugger. */
460 ( void ) hal_eth_init_status;
462 /* Set the TxDesc and RxDesc pointers. */
463 xETH.TxDesc = DMATxDscrTab;
464 xETH.RxDesc = DMARxDscrTab;
466 /* Make sure that all unused fields are cleared. */
467 memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
468 memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
470 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
472 /* Initialize Tx Descriptors list: Chain Mode */
473 DMATxDescToClear = DMATxDscrTab;
475 #endif /* ipconfigZERO_COPY_TX_DRIVER */
477 /* Initialise TX-descriptors. */
478 prvDMATxDescListInit();
480 /* Initialise RX-descriptors. */
481 prvDMARxDescListInit();
483 #if( ipconfigUSE_LLMNR != 0 )
485 /* Program the LLMNR address at index 1. */
486 prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );
490 /* Force a negotiation with the Switch or Router and wait for LS. */
491 prvEthernetUpdateConfig( pdTRUE );
493 /* The deferred interrupt handler task is created at the highest
494 possible priority to ensure the interrupt handler can return directly
495 to it. The task's handle is stored in xEMACTaskHandle so interrupts can
496 notify the task when there is something to process. */
497 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
498 } /* if( xEMACTaskHandle == NULL ) */
500 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
502 xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
504 FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
508 /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
509 and it will keep on checking the PHY and set ulPHYLinkStatus when necessary. */
511 FreeRTOS_printf( ( "Link Status still low\n" ) ) ;
513 /* When returning non-zero, the stack will become active and
514 start DHCP (in configured) */
517 /*-----------------------------------------------------------*/
519 static void prvDMATxDescListInit()
521 ETH_DMADescTypeDef *pxDMADescriptor;
524 /* Get the pointer on the first member of the descriptor list */
525 pxDMADescriptor = DMATxDscrTab;
527 /* Fill each DMA descriptor with the right values */
528 for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )
530 /* Set Second Address Chained bit */
531 pxDMADescriptor->Status = ETH_DMATXDESC_TCH;
533 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
535 /* Set Buffer1 address pointer */
536 pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );
540 if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )
542 /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */
543 pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
546 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
547 if( xIndex < ETH_TXBUFNB - 1 )
549 /* Set next descriptor address register with next descriptor base address */
550 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
554 /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
555 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;
559 /* Set Transmit Descriptor List Address Register */
560 xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;
562 /*-----------------------------------------------------------*/
564 static void prvDMARxDescListInit()
566 ETH_DMADescTypeDef *pxDMADescriptor;
572 /* Get the pointer on the first member of the descriptor list */
573 pxDMADescriptor = DMARxDscrTab;
575 /* Fill each DMA descriptor with the right values */
576 for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )
579 /* Set Buffer1 size and Second Address Chained bit */
580 pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
582 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
584 /* Set Buffer1 address pointer */
585 NetworkBufferDescriptor_t *pxBuffer;
587 pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );
588 /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'
589 Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */
590 configASSERT( pxBuffer != NULL );
591 if( pxBuffer != NULL )
593 pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;
594 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
599 /* Set Buffer1 address pointer */
600 pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );
601 /* Set Own bit of the Rx descriptor Status */
602 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
606 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
607 if( xIndex < ETH_RXBUFNB - 1 )
609 /* Set next descriptor address register with next descriptor base address */
610 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );
614 /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
615 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;
619 /* Set Receive Descriptor List Address Register */
620 xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
622 /*-----------------------------------------------------------*/
624 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)
628 /* Calculate the selected MAC address high register. */
629 ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
631 /* Load the selected MAC address high register. */
632 ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
634 /* Calculate the selected MAC address low register. */
635 ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
637 /* Load the selected MAC address low register */
638 ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
640 /*-----------------------------------------------------------*/
642 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
644 BaseType_t xReturn = pdFAIL;
645 uint32_t ulTransmitSize = 0;
646 __IO ETH_DMADescTypeDef *pxDmaTxDesc;
647 /* Do not wait too long for a free TX DMA buffer. */
648 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
650 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
652 ProtocolPacket_t *pxPacket;
654 /* If the peripheral must calculate the checksum, it wants
655 the protocol checksum to have a value of zero. */
656 pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );
658 if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )
660 pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
665 /* Open a do {} while ( 0 ) loop to be able to call break. */
668 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
670 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
672 if( xTXDescriptorSemaphore == NULL )
676 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
678 /* Time-out waiting for a free TX descriptor. */
682 #endif /* ipconfigZERO_COPY_TX_DRIVER */
684 /* This function does the actual transmission of the packet. The packet is
685 contained in 'pxDescriptor' that is passed to the function. */
686 pxDmaTxDesc = xETH.TxDesc;
688 /* Is this buffer available? */
689 if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 )
691 /* Is this buffer available? */
692 /* Get bytes in current buffer. */
693 ulTransmitSize = pxDescriptor->xDataLength;
695 if( ulTransmitSize > ETH_TX_BUF_SIZE )
697 ulTransmitSize = ETH_TX_BUF_SIZE;
700 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
702 /* Copy the bytes. */
703 memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
704 pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL;
708 /* Move the buffer. */
709 pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;
710 /* Ask to set the IPv4 checksum.
711 Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
712 pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
713 /* The Network Buffer has been passed to DMA, no need to release it. */
714 bReleaseAfterSend = pdFALSE_UNSIGNED;
716 #endif /* ipconfigZERO_COPY_TX_DRIVER */
718 /* Prepare transmit descriptors to give to DMA. */
720 /* Set LAST and FIRST segment */
721 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
723 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
724 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
725 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
727 /* Point to next descriptor */
728 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
730 /* Resume DMA transmission*/
731 xETH.Instance->DMATPDR = 0;
732 iptraceNETWORK_INTERFACE_TRANSMIT();
738 /* The PHY has no Link Status, packet shall be dropped. */
741 /* The buffer has been sent so can be released. */
742 if( bReleaseAfterSend != pdFALSE )
744 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
749 /*-----------------------------------------------------------*/
751 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )
753 const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;
755 switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )
757 case ipARP_FRAME_TYPE:
758 /* Check it later. */
760 case ipIPv4_FRAME_TYPE:
764 /* Refuse the packet. */
768 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
770 const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);
771 uint32_t ulDestinationIPAddress;
773 /* Ensure that the incoming packet is not fragmented (only outgoing packets
774 * can be fragmented) as these are the only handled IP frames currently. */
775 if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )
779 /* HT: Might want to make the following configurable because
780 * most IP messages have a standard length of 20 bytes */
782 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
783 * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
784 if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )
789 ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
790 /* Is the packet for this node? */
791 if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
792 /* Is it a broadcast address x.x.x.255 ? */
793 ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&
794 #if( ipconfigUSE_LLMNR == 1 )
795 ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
797 ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {
798 FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );
802 if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )
804 uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;
806 if( ( xPortHasUDPSocket( port ) == pdFALSE )
807 #if ipconfigUSE_LLMNR == 1
808 && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )
810 #if ipconfigUSE_NBNS == 1
811 && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )
813 #if ipconfigUSE_DNS == 1
814 && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )
817 /* Drop this packet, not for this device. */
822 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
825 /*-----------------------------------------------------------*/
827 static BaseType_t prvNetworkInterfaceInput( void )
829 NetworkBufferDescriptor_t *pxCurDescriptor;
830 NetworkBufferDescriptor_t *pxNewDescriptor = NULL;
831 BaseType_t xReceivedLength, xAccepted;
832 __IO ETH_DMADescTypeDef *pxDMARxDescriptor;
833 xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
834 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
837 pxDMARxDescriptor = xETH.RxDesc;
839 if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 )
841 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
842 xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
844 pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;
846 /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
848 /* Selects the next DMA Rx descriptor list for next buffer to read */
849 xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;
856 /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */
857 /* In order to make the code easier and faster, only packets in a single buffer
858 will be accepted. This can be done by making the buffers large enough to
859 hold a complete Ethernet packet (1536 bytes). */
860 if( xReceivedLength > 0ul && xReceivedLength < ETH_RX_BUF_SIZE )
862 if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )
864 /* Not an Ethernet frame-type or a checmsum error. */
869 /* See if this packet must be handled. */
870 xAccepted = xMayAcceptPacket( pucBuffer );
873 if( xAccepted != pdFALSE )
875 /* The packet wil be accepted, but check first if a new Network Buffer can
876 be obtained. If not, the packet will still be dropped. */
877 pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );
879 if( pxNewDescriptor == NULL )
881 /* A new descriptor can not be allocated now. This packet will be dropped. */
885 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
887 /* Find out which Network Buffer was originally passed to the descriptor. */
888 pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
889 configASSERT( pxCurDescriptor != NULL );
893 /* In this mode, the two descriptors are the same. */
894 pxCurDescriptor = pxNewDescriptor;
895 if( pxNewDescriptor != NULL )
897 /* The packet is acepted and a new Network Buffer was created,
898 copy data to the Network Bufffer. */
899 memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );
904 if( xAccepted != pdFALSE )
906 pxCurDescriptor->xDataLength = xReceivedLength;
907 xRxEvent.pvData = ( void * ) pxCurDescriptor;
909 /* Pass the data to the TCP/IP task for processing. */
910 if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )
912 /* Could not send the descriptor into the TCP/IP stack, it
914 vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );
915 iptraceETHERNET_RX_EVENT_LOST();
919 iptraceNETWORK_INTERFACE_RECEIVE();
923 /* Release descriptors to DMA */
924 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
926 /* Set Buffer1 address pointer */
927 if( pxNewDescriptor != NULL )
929 pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;
933 /* The packet was dropped and the same Network
934 Buffer will be used to receive a new packet. */
937 #endif /* ipconfigZERO_COPY_RX_DRIVER */
939 /* Set Buffer1 size and Second Address Chained bit */
940 pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
941 pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
943 /* When Rx Buffer unavailable flag is set clear it and resume
945 if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
947 /* Clear RBUS ETHERNET DMA flag. */
948 xETH.Instance->DMASR = ETH_DMASR_RBUS;
950 /* Resume DMA reception. */
951 xETH.Instance->DMARPDR = 0;
955 return ( xReceivedLength > 0 );
957 /*-----------------------------------------------------------*/
959 void vMACBProbePhy( void )
961 uint32_t ulConfig, ulAdvertise, ulLower, ulUpper, ulMACPhyID, ulValue;
963 TickType_t xRemTime = 0;
964 #if( EXPECTED_PHY_ID == PHY_ID_DP83848I )
965 uint32_t ulPhyControl;
968 HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_03_PHYSID2, &ulLower);
969 HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_02_PHYSID1, &ulUpper);
971 ulMACPhyID = ( ( ulUpper << 16 ) & 0xFFFF0000 ) | ( ulLower & 0xFFF0 );
973 /* The expected ID for the 'LAN8720' is 0x0007c0f0. */
974 /* The expected ID for the 'DP83848I' is 0x20005C90. */
976 FreeRTOS_printf( ( "PHY ID %lX (%s)\n", ulMACPhyID,
977 ( ulMACPhyID == EXPECTED_PHY_ID ) ? "OK" : "Unknown" ) );
979 /* Remove compiler warning if FreeRTOS_printf() is not defined. */
982 /* Set advertise register. */
983 if( ( xPHYProperties.speed == PHY_SPEED_AUTO ) && ( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) )
985 ulAdvertise = ADVERTISE_CSMA | ADVERTISE_ALL;
986 /* Reset auto-negotiation capability. */
990 ulAdvertise = ADVERTISE_CSMA;
992 if( xPHYProperties.speed == PHY_SPEED_AUTO )
994 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
996 ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_100FULL;
1000 ulAdvertise |= ADVERTISE_10HALF | ADVERTISE_100HALF;
1003 else if( xPHYProperties.duplex == PHY_DUPLEX_AUTO )
1005 if( xPHYProperties.speed == PHY_SPEED_10 )
1007 ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_10HALF;
1011 ulAdvertise |= ADVERTISE_100FULL | ADVERTISE_100HALF;
1014 else if( xPHYProperties.speed == PHY_SPEED_100 )
1016 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
1018 ulAdvertise |= ADVERTISE_100FULL;
1022 ulAdvertise |= ADVERTISE_100HALF;
1027 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
1029 ulAdvertise |= ADVERTISE_10FULL;
1033 ulAdvertise |= ADVERTISE_10HALF;
1038 /* Read Control register. */
1039 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
1041 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig | BMCR_RESET );
1042 xRemTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );
1043 vTaskSetTimeOutState( &xPhyTime );
1047 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulValue );
1048 if( ( ulValue & BMCR_RESET ) == 0 )
1050 FreeRTOS_printf( ( "BMCR_RESET ready\n" ) );
1053 if( xTaskCheckForTimeOut( &xPhyTime, &xRemTime ) != pdFALSE )
1055 FreeRTOS_printf( ( "BMCR_RESET timed out\n" ) );
1059 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig & ~BMCR_RESET );
1061 vTaskDelay( pdMS_TO_TICKS( 50ul ) );
1063 /* Write advertise register. */
1064 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulAdvertise );
1067 AN_EN AN1 AN0 Forced Mode
1068 0 0 0 10BASE-T, Half-Duplex
1069 0 0 1 10BASE-T, Full-Duplex
1070 0 1 0 100BASE-TX, Half-Duplex
1071 0 1 1 100BASE-TX, Full-Duplex
1072 AN_EN AN1 AN0 Advertised Mode
1073 1 0 0 10BASE-T, Half/Full-Duplex
1074 1 0 1 100BASE-TX, Half/Full-Duplex
1075 1 1 0 10BASE-T Half-Duplex
1076 100BASE-TX, Half-Duplex
1077 1 1 1 10BASE-T, Half/Full-Duplex
1078 100BASE-TX, Half/Full-Duplex
1081 /* Read Control register. */
1082 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
1084 ulConfig &= ~( BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX );
1086 /* HT 12/9/14: always set AN-restart and AN-enable, even though the choices
1088 ulConfig |= (BMCR_ANRESTART | BMCR_ANENABLE);
1090 if( xPHYProperties.speed == PHY_SPEED_100 )
1092 ulConfig |= BMCR_SPEED100;
1094 else if( xPHYProperties.speed == PHY_SPEED_10 )
1096 ulConfig &= ~BMCR_SPEED100;
1099 if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
1101 ulConfig |= BMCR_FULLDPLX;
1103 else if( xPHYProperties.duplex == PHY_DUPLEX_HALF )
1105 ulConfig &= ~BMCR_FULLDPLX;
1108 #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
1111 #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
1113 /* Read PHY Control register. */
1114 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_19_PHYCR, &ulPhyControl );
1116 /* Clear bits which might get set: */
1117 ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
1119 if( xPHYProperties.mdix == PHY_MDIX_AUTO )
1121 ulPhyControl |= PHYCR_MDIX_EN;
1123 else if( xPHYProperties.mdix == PHY_MDIX_CROSSED )
1125 /* Force direct link = Use crossed RJ45 cable. */
1126 ulPhyControl &= ~PHYCR_MDIX_FORCE;
1130 /* Force crossed link = Use direct RJ45 cable. */
1131 ulPhyControl |= PHYCR_MDIX_FORCE;
1133 /* update PHY Control Register. */
1134 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_19_PHYCR, ulPhyControl );
1137 FreeRTOS_printf( ( "+TCP: advertise: %lX config %lX\n", ulAdvertise, ulConfig ) );
1139 /* Now the two values to global values for later use. */
1140 ulBCRvalue = ulConfig;
1141 ulACRValue = ulAdvertise;
1143 /*-----------------------------------------------------------*/
1145 static void prvEthernetUpdateConfig( BaseType_t xForce )
1147 __IO uint32_t ulTimeout = 0;
1148 uint32_t ulRegValue = 0;
1150 FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS %d Force %d\n",
1151 ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ,
1154 if( ( xForce != pdFALSE ) || ( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) )
1156 /* Restart the auto-negotiation. */
1157 if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
1159 /* Enable Auto-Negotiation. */
1160 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue | BMCR_ANRESTART );
1161 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulACRValue);
1163 /* Wait until the auto-negotiation will be completed */
1167 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue );
1168 } while( ( ( ulRegValue & PHY_AUTONEGO_COMPLETE) == 0 ) && ( ulTimeout < PHY_READ_TO ) );
1170 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue & ~BMCR_ANRESTART );
1172 if( ulTimeout < PHY_READ_TO )
1174 /* Reset Timeout counter. */
1177 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue);
1178 if( ( ulRegValue & BMSR_LINK_STATUS ) != 0 )
1180 ulPHYLinkStatus |= BMSR_LINK_STATUS;
1184 ulPHYLinkStatus &= ~( BMSR_LINK_STATUS );
1187 #if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
1189 /* 31 RW PHY Special Control Status */
1190 uint32_t ulControlStatus;
1192 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_1F_PHYSPCS, &ulControlStatus);
1194 if( ( ulControlStatus & PHYSPCS_FULL_DUPLEX ) != 0 )
1196 ulRegValue |= PHY_DUPLEX_STATUS;
1198 if( ( ulControlStatus & PHYSPCS_SPEED_MASK ) == PHYSPCS_SPEED_10 )
1200 ulRegValue |= PHY_SPEED_STATUS;
1204 #elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
1206 /* Read the result of the auto-negotiation. */
1207 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_10_PHY_SR, &ulRegValue);
1210 FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",
1212 (ulRegValue & PHY_DUPLEX_STATUS) ? "full" : "half",
1213 (ulRegValue & PHY_SPEED_STATUS) ? 10 : 100,
1214 ((ulPHYLinkStatus |= BMSR_LINK_STATUS) != 0) ? "high" : "low" ) );
1216 /* Configure the MAC with the Duplex Mode fixed by the
1217 auto-negotiation process. */
1218 if( ( ulRegValue & PHY_DUPLEX_STATUS ) != ( uint32_t ) RESET )
1220 /* Set Ethernet duplex mode to Full-duplex following the
1221 auto-negotiation. */
1222 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
1226 /* Set Ethernet duplex mode to Half-duplex following the
1227 auto-negotiation. */
1228 xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
1231 /* Configure the MAC with the speed fixed by the
1232 auto-negotiation process. */
1233 if( ( ulRegValue & PHY_SPEED_STATUS) != 0 )
1235 /* Set Ethernet speed to 10M following the
1236 auto-negotiation. */
1237 xETH.Init.Speed = ETH_SPEED_10M;
1241 /* Set Ethernet speed to 100M following the
1242 auto-negotiation. */
1243 xETH.Init.Speed = ETH_SPEED_100M;
1245 } /* if( ulTimeout < PHY_READ_TO ) */
1247 else /* AutoNegotiation Disable */
1251 /* Check parameters */
1252 assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
1253 assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
1255 /* Set MAC Speed and Duplex Mode to PHY */
1256 usValue = ( uint16_t ) ( xETH.Init.DuplexMode >> 3 ) | ( uint16_t ) ( xETH.Init.Speed >> 1 );
1257 HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, usValue );
1260 /* ETHERNET MAC Re-Configuration */
1261 HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);
1263 /* Restart MAC interface */
1264 HAL_ETH_Start( &xETH);
1268 /* Stop MAC interface */
1269 HAL_ETH_Stop( &xETH );
1272 /*-----------------------------------------------------------*/
1274 BaseType_t xGetPhyLinkStatus( void )
1278 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
1289 /*-----------------------------------------------------------*/
1291 static void prvEMACHandlerTask( void *pvParameters )
1294 TickType_t xPhyRemTime;
1295 UBaseType_t uxLastMinBufferCount = 0;
1296 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1297 UBaseType_t uxLastMinQueueSpace = 0;
1299 UBaseType_t uxCurrentCount;
1300 BaseType_t xResult = 0;
1302 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
1304 /* Remove compiler warnings about unused parameters. */
1305 ( void ) pvParameters;
1307 vTaskSetTimeOutState( &xPhyTime );
1308 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
1312 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
1313 if( uxLastMinBufferCount != uxCurrentCount )
1315 /* The logging produced below may be helpful
1316 while tuning +TCP: see how many buffers are in use. */
1317 uxLastMinBufferCount = uxCurrentCount;
1318 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
1319 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
1322 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
1323 if( xTXDescriptorSemaphore != NULL )
1325 static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
1327 uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
1328 if( uxLowestSemCount > uxCurrentCount )
1330 uxLowestSemCount = uxCurrentCount;
1331 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
1336 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1338 uxCurrentCount = uxGetMinimumIPQueueSpace();
1339 if( uxLastMinQueueSpace != uxCurrentCount )
1341 /* The logging produced below may be helpful
1342 while tuning +TCP: see how many buffers are in use. */
1343 uxLastMinQueueSpace = uxCurrentCount;
1344 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
1347 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
1349 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
1351 /* No events to process now, wait for the next. */
1352 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
1355 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
1357 ulISREvents &= ~EMAC_IF_RX_EVENT;
1359 xResult = prvNetworkInterfaceInput();
1362 while( prvNetworkInterfaceInput() > 0 )
1368 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
1370 /* Code to release TX buffers if zero-copy is used. */
1371 ulISREvents &= ~EMAC_IF_TX_EVENT;
1372 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
1374 /* Check if DMA packets have been delivered. */
1380 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
1382 /* Future extension: logging about errors that occurred. */
1383 ulISREvents &= ~EMAC_IF_ERR_EVENT;
1388 /* A packet was received. No need to check for the PHY status now,
1389 but set a timer to check it later on. */
1390 vTaskSetTimeOutState( &xPhyTime );
1391 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
1394 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
1396 HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &xStatus );
1397 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
1399 ulPHYLinkStatus = xStatus;
1400 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
1401 prvEthernetUpdateConfig( pdFALSE );
1404 vTaskSetTimeOutState( &xPhyTime );
1405 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
1407 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
1411 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
1416 /*-----------------------------------------------------------*/
1418 void ETH_IRQHandler( void )
1420 HAL_ETH_IRQHandler( &xETH );