2 * Some constants, hardware definitions and comments taken from ST's HAL driver
\r
3 * library, COPYRIGHT(c) 2015 STMicroelectronics.
\r
7 * FreeRTOS+TCP V2.0.3
\r
8 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
10 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
11 * this software and associated documentation files (the "Software"), to deal in
\r
12 * the Software without restriction, including without limitation the rights to
\r
13 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
14 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
15 * subject to the following conditions:
\r
17 * The above copyright notice and this permission notice shall be included in all
\r
18 * copies or substantial portions of the Software.
\r
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
23 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
27 * http://aws.amazon.com/freertos
\r
28 * http://www.FreeRTOS.org
\r
32 /* Standard includes. */
\r
37 /* FreeRTOS includes. */
\r
38 #include "FreeRTOS.h"
\r
43 /* FreeRTOS+TCP includes. */
\r
44 #include "FreeRTOS_IP.h"
\r
45 #include "FreeRTOS_Sockets.h"
\r
46 #include "FreeRTOS_IP_Private.h"
\r
47 #include "FreeRTOS_DNS.h"
\r
48 #include "NetworkBufferManagement.h"
\r
49 #include "NetworkInterface.h"
\r
50 #include "phyHandling.h"
\r
54 #include "stm32f7xx_hal.h"
\r
56 #include "stm32f4xx_hal.h"
\r
59 /* Interrupt events to process. Currently only the Rx event is processed
\r
60 although code for other events is included to allow for possible future
\r
62 #define EMAC_IF_RX_EVENT 1UL
\r
63 #define EMAC_IF_TX_EVENT 2UL
\r
64 #define EMAC_IF_ERR_EVENT 4UL
\r
65 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
67 #define ETH_DMA_ALL_INTS \
\r
68 ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \
\r
69 ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \
\r
70 ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
\r
74 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
\r
77 * Most users will want a PHY that negotiates about
\r
78 * the connection properties: speed, dmix and duplex.
\r
79 * On some rare cases, you want to select what is being
\r
80 * advertised, properties like MDIX and duplex.
\r
83 #if !defined( ipconfigETHERNET_AN_ENABLE )
\r
84 /* Enable auto-negotiation */
\r
85 #define ipconfigETHERNET_AN_ENABLE 1
\r
88 #if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )
\r
89 #define ipconfigETHERNET_AUTO_CROSS_ENABLE 1
\r
92 #if( ipconfigETHERNET_AN_ENABLE == 0 )
\r
94 * The following three defines are only used in case there
\r
95 * is no auto-negotiation.
\r
97 #if !defined( ipconfigETHERNET_CROSSED_LINK )
\r
98 #define ipconfigETHERNET_CROSSED_LINK 1
\r
101 #if !defined( ipconfigETHERNET_USE_100MB )
\r
102 #define ipconfigETHERNET_USE_100MB 1
\r
105 #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )
\r
106 #define ipconfigETHERNET_USE_FULL_DUPLEX 1
\r
108 #endif /* ipconfigETHERNET_AN_ENABLE == 0 */
\r
110 /* Default the size of the stack used by the EMAC deferred handler task to twice
\r
111 the size of the stack used by the idle task - but allow this to be overridden in
\r
112 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
113 #ifndef configEMAC_TASK_STACK_SIZE
\r
114 #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
\r
117 /* Two choices must be made: RMII versus MII,
\r
118 and the index of the PHY in use ( between 0 and 31 ). */
\r
119 #ifndef ipconfigUSE_RMII
\r
121 #define ipconfigUSE_RMII 1
\r
123 #define ipconfigUSE_RMII 0
\r
124 #endif /* STM32F7xx */
\r
125 #endif /* ipconfigUSE_RMII */
\r
129 /*-----------------------------------------------------------*/
\r
132 * A deferred interrupt handler task that processes
\r
134 static void prvEMACHandlerTask( void *pvParameters );
\r
137 * Force a negotiation with the Switch or Router and wait for LS.
\r
139 static void prvEthernetUpdateConfig( BaseType_t xForce );
\r
142 * See if there is a new packet and forward it to the IP-task.
\r
144 static BaseType_t prvNetworkInterfaceInput( void );
\r
146 #if( ipconfigUSE_LLMNR != 0 )
\r
148 * For LLMNR, an extra MAC-address must be configured to
\r
149 * be able to receive the multicast messages.
\r
151 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);
\r
155 * Check if a given packet should be accepted.
\r
157 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );
\r
160 * Initialise the TX descriptors.
\r
162 static void prvDMATxDescListInit( void );
\r
165 * Initialise the RX descriptors.
\r
167 static void prvDMARxDescListInit( void );
\r
169 /* After packets have been sent, the network
\r
170 buffers will be released. */
\r
171 static void vClearTXBuffers( void );
\r
173 /*-----------------------------------------------------------*/
\r
175 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
176 the Rx interrupt is handled, although code is included for other events to
\r
177 enable future expansion. */
\r
178 static volatile uint32_t ulISREvents;
\r
180 #if( ipconfigUSE_LLMNR == 1 )
\r
181 static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
\r
184 static EthernetPhy_t xPhyObject;
\r
186 /* Ethernet handle. */
\r
187 static ETH_HandleTypeDef xETH;
\r
189 /* xTXDescriptorSemaphore is a counting semaphore with
\r
190 a maximum count of ETH_TXBUFNB, which is the number of
\r
191 DMA TX descriptors. */
\r
192 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
\r
195 * Note: it is adviced to define both
\r
197 * #define ipconfigZERO_COPY_RX_DRIVER 1
\r
198 * #define ipconfigZERO_COPY_TX_DRIVER 1
\r
200 * The method using memcpy is slower and probaly uses more RAM memory.
\r
201 * The possibility is left in the code just for comparison.
\r
203 * It is adviced to define ETH_TXBUFNB at least 4. Note that no
\r
204 * TX buffers are allocated in a zero-copy driver.
\r
206 /* MAC buffers: ---------------------------------------------------------*/
\r
208 /* Put the DMA descriptors in '.first_data'.
\r
209 This is important for STM32F7, which has an L1 data cache.
\r
210 The first 64KB of the SRAM is not cached. */
\r
212 /* Ethernet Rx MA Descriptor */
\r
213 __attribute__ ((aligned (32)))
\r
214 __attribute__ ((section(".first_data")))
\r
215 ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ];
\r
217 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
\r
218 /* Ethernet Receive Buffer */
\r
219 __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END;
\r
222 /* Ethernet Tx DMA Descriptor */
\r
223 __attribute__ ((aligned (32)))
\r
224 __attribute__ ((section(".first_data")))
\r
225 ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ];
\r
227 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
\r
228 /* Ethernet Transmit Buffer */
\r
229 __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END;
\r
232 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
233 /* DMATxDescToClear points to the next TX DMA descriptor
\r
234 that must be cleared by vClearTXBuffers(). */
\r
235 static __IO ETH_DMADescTypeDef *DMATxDescToClear;
\r
238 /* ucMACAddress as it appears in main.c */
\r
239 extern const uint8_t ucMACAddress[ 6 ];
\r
241 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
242 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
243 related interrupts. */
\r
244 static TaskHandle_t xEMACTaskHandle = NULL;
\r
246 /* For local use only: describe the PHY's properties: */
\r
247 const PhyProperties_t xPHYProperties =
\r
249 #if( ipconfigETHERNET_AN_ENABLE != 0 )
\r
250 .ucSpeed = PHY_SPEED_AUTO,
\r
251 .ucDuplex = PHY_DUPLEX_AUTO,
\r
253 #if( ipconfigETHERNET_USE_100MB != 0 )
\r
254 .ucSpeed = PHY_SPEED_100,
\r
256 .ucSpeed = PHY_SPEED_10,
\r
259 #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
\r
260 .duplex = PHY_DUPLEX_FULL,
\r
262 .duplex = PHY_DUPLEX_HALF,
\r
266 #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
\r
267 .ucMDI_X = PHY_MDIX_AUTO,
\r
268 #elif( ipconfigETHERNET_CROSSED_LINK != 0 )
\r
269 .ucMDI_X = PHY_MDIX_CROSSED,
\r
271 .ucMDI_X = PHY_MDIX_DIRECT,
\r
275 /*-----------------------------------------------------------*/
\r
277 void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
\r
279 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
281 /* Ethernet RX-Complete callback function, elsewhere declared as weak. */
\r
282 ulISREvents |= EMAC_IF_RX_EVENT;
\r
283 /* Wakeup the prvEMACHandlerTask. */
\r
284 if( xEMACTaskHandle != NULL )
\r
286 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
287 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
290 /*-----------------------------------------------------------*/
\r
292 void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )
\r
294 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
296 /* This call-back is only useful in case packets are being sent
\r
297 zero-copy. Once they're sent, the buffers will be released
\r
298 by the function vClearTXBuffers(). */
\r
299 ulISREvents |= EMAC_IF_TX_EVENT;
\r
300 /* Wakeup the prvEMACHandlerTask. */
\r
301 if( xEMACTaskHandle != NULL )
\r
303 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
\r
304 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
308 /*-----------------------------------------------------------*/
\r
310 static void vClearTXBuffers()
\r
312 __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc;
\r
313 size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
314 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
315 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
316 uint8_t *ucPayLoad;
\r
319 /* This function is called after a TX-completion interrupt.
\r
320 It will release each Network Buffer used in xNetworkInterfaceOutput().
\r
321 'uxCount' represents the number of descriptors given to DMA for transmission.
\r
322 After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */
\r
323 while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) )
\r
325 if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) )
\r
329 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
\r
331 ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
\r
333 if( ucPayLoad != NULL )
\r
335 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );
\r
336 if( pxNetworkBuffer != NULL )
\r
338 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;
\r
340 DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
\r
343 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
345 DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );
\r
348 /* Tell the counting semaphore that one more TX descriptor is available. */
\r
349 xSemaphoreGive( xTXDescriptorSemaphore );
\r
352 /*-----------------------------------------------------------*/
\r
354 BaseType_t xNetworkInterfaceInitialise( void )
\r
356 HAL_StatusTypeDef hal_eth_init_status;
\r
357 BaseType_t xResult;
\r
359 if( xEMACTaskHandle == NULL )
\r
361 if( xTXDescriptorSemaphore == NULL )
\r
363 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
\r
364 configASSERT( xTXDescriptorSemaphore );
\r
367 /* Initialise ETH */
\r
369 xETH.Instance = ETH;
\r
370 xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
\r
371 xETH.Init.Speed = ETH_SPEED_100M;
\r
372 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
\r
373 /* Value of PhyAddress doesn't matter, will be probed for. */
\r
374 xETH.Init.PhyAddress = 0;
\r
376 xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;
\r
377 xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
\r
379 /* using the ETH_CHECKSUM_BY_HARDWARE option:
\r
380 both the IP and the protocol checksums will be calculated
\r
381 by the peripheral. */
\r
382 xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
\r
384 #if( ipconfigUSE_RMII != 0 )
\r
386 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
\r
390 xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
\r
392 #endif /* ipconfigUSE_RMII */
\r
394 hal_eth_init_status = HAL_ETH_Init( &xETH );
\r
396 /* Only for inspection by debugger. */
\r
397 ( void ) hal_eth_init_status;
\r
399 /* Set the TxDesc and RxDesc pointers. */
\r
400 xETH.TxDesc = DMATxDscrTab;
\r
401 xETH.RxDesc = DMARxDscrTab;
\r
403 /* Make sure that all unused fields are cleared. */
\r
404 memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
\r
405 memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
\r
407 /* Initialize Tx Descriptors list: Chain Mode */
\r
408 DMATxDescToClear = DMATxDscrTab;
\r
410 /* Initialise TX-descriptors. */
\r
411 prvDMATxDescListInit();
\r
413 /* Initialise RX-descriptors. */
\r
414 prvDMARxDescListInit();
\r
416 #if( ipconfigUSE_LLMNR != 0 )
\r
418 /* Program the LLMNR address at index 1. */
\r
419 prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );
\r
423 /* Force a negotiation with the Switch or Router and wait for LS. */
\r
424 prvEthernetUpdateConfig( pdTRUE );
\r
426 /* The deferred interrupt handler task is created at the highest
\r
427 possible priority to ensure the interrupt handler can return directly
\r
428 to it. The task's handle is stored in xEMACTaskHandle so interrupts can
\r
429 notify the task when there is something to process. */
\r
430 xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
431 } /* if( xEMACTaskHandle == NULL ) */
\r
433 if( xPhyObject.ulLinkStatusMask != 0 )
\r
435 xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
\r
437 FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
\r
441 /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
\r
442 and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
\r
444 FreeRTOS_printf( ( "Link Status still low\n" ) ) ;
\r
446 /* When returning non-zero, the stack will become active and
\r
447 start DHCP (in configured) */
\r
450 /*-----------------------------------------------------------*/
\r
452 static void prvDMATxDescListInit()
\r
454 ETH_DMADescTypeDef *pxDMADescriptor;
\r
457 /* Get the pointer on the first member of the descriptor list */
\r
458 pxDMADescriptor = DMATxDscrTab;
\r
460 /* Fill each DMA descriptor with the right values */
\r
461 for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ )
\r
463 /* Set Second Address Chained bit */
\r
464 pxDMADescriptor->Status = ETH_DMATXDESC_TCH;
\r
466 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
\r
468 /* Set Buffer1 address pointer */
\r
469 pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );
\r
473 if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE )
\r
475 /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */
\r
476 pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
\r
479 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
\r
480 if( xIndex < ETH_TXBUFNB - 1 )
\r
482 /* Set next descriptor address register with next descriptor base address */
\r
483 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );
\r
487 /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
\r
488 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;
\r
492 /* Set Transmit Descriptor List Address Register */
\r
493 xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;
\r
495 /*-----------------------------------------------------------*/
\r
497 static void prvDMARxDescListInit()
\r
499 ETH_DMADescTypeDef *pxDMADescriptor;
\r
505 /* Get the pointer on the first member of the descriptor list */
\r
506 pxDMADescriptor = DMARxDscrTab;
\r
508 /* Fill each DMA descriptor with the right values */
\r
509 for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ )
\r
512 /* Set Buffer1 size and Second Address Chained bit */
\r
513 pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
\r
515 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
517 /* Set Buffer1 address pointer */
\r
518 NetworkBufferDescriptor_t *pxBuffer;
\r
520 pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );
\r
521 /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'
\r
522 Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */
\r
523 configASSERT( pxBuffer != NULL );
\r
524 if( pxBuffer != NULL )
\r
526 pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;
\r
527 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
\r
532 /* Set Buffer1 address pointer */
\r
533 pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );
\r
534 /* Set Own bit of the Rx descriptor Status */
\r
535 pxDMADescriptor->Status = ETH_DMARXDESC_OWN;
\r
539 /* Initialize the next descriptor with the Next Descriptor Polling Enable */
\r
540 if( xIndex < ETH_RXBUFNB - 1 )
\r
542 /* Set next descriptor address register with next descriptor base address */
\r
543 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );
\r
547 /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
\r
548 pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;
\r
552 /* Set Receive Descriptor List Address Register */
\r
553 xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;
\r
555 /*-----------------------------------------------------------*/
\r
557 static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr)
\r
559 uint32_t ulTempReg;
\r
561 /* Calculate the selected MAC address high register. */
\r
562 ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
\r
564 /* Load the selected MAC address high register. */
\r
565 ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
\r
567 /* Calculate the selected MAC address low register. */
\r
568 ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
\r
570 /* Load the selected MAC address low register */
\r
571 ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
\r
573 /*-----------------------------------------------------------*/
\r
575 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
\r
577 BaseType_t xReturn = pdFAIL;
\r
578 uint32_t ulTransmitSize = 0;
\r
579 __IO ETH_DMADescTypeDef *pxDmaTxDesc;
\r
580 /* Do not wait too long for a free TX DMA buffer. */
\r
581 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
\r
583 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
\r
585 ProtocolPacket_t *pxPacket;
\r
587 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
589 configASSERT( bReleaseAfterSend != 0 );
\r
591 #endif /* ipconfigZERO_COPY_RX_DRIVER */
\r
593 /* If the peripheral must calculate the checksum, it wants
\r
594 the protocol checksum to have a value of zero. */
\r
595 pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );
\r
597 if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )
\r
599 pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
\r
604 /* Open a do {} while ( 0 ) loop to be able to call break. */
\r
607 if( xPhyObject.ulLinkStatusMask != 0 )
\r
609 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
\r
611 /* Time-out waiting for a free TX descriptor. */
\r
615 /* This function does the actual transmission of the packet. The packet is
\r
616 contained in 'pxDescriptor' that is passed to the function. */
\r
617 pxDmaTxDesc = xETH.TxDesc;
\r
619 /* Is this buffer available? */
\r
620 configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );
\r
623 /* Is this buffer available? */
\r
624 /* Get bytes in current buffer. */
\r
625 ulTransmitSize = pxDescriptor->xDataLength;
\r
627 if( ulTransmitSize > ETH_TX_BUF_SIZE )
\r
629 ulTransmitSize = ETH_TX_BUF_SIZE;
\r
632 #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
\r
634 /* Copy the bytes. */
\r
635 memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
\r
639 /* Move the buffer. */
\r
640 pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;
\r
641 /* The Network Buffer has been passed to DMA, no need to release it. */
\r
642 bReleaseAfterSend = pdFALSE_UNSIGNED;
\r
644 #endif /* ipconfigZERO_COPY_TX_DRIVER */
\r
646 /* Ask to set the IPv4 checksum.
\r
647 Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
\r
648 pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
\r
650 /* Prepare transmit descriptors to give to DMA. */
\r
652 /* Set LAST and FIRST segment */
\r
653 pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;
\r
654 /* Set frame size */
\r
655 pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );
\r
656 /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
\r
657 pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;
\r
659 /* Point to next descriptor */
\r
660 xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
\r
661 /* Ensure completion of memory access */
\r
663 /* Resume DMA transmission*/
\r
664 xETH.Instance->DMATPDR = 0;
\r
665 iptraceNETWORK_INTERFACE_TRANSMIT();
\r
671 /* The PHY has no Link Status, packet shall be dropped. */
\r
674 /* The buffer has been sent so can be released. */
\r
675 if( bReleaseAfterSend != pdFALSE )
\r
677 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
\r
682 /*-----------------------------------------------------------*/
\r
684 static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer )
\r
686 const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;
\r
688 switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType )
\r
690 case ipARP_FRAME_TYPE:
\r
691 /* Check it later. */
\r
693 case ipIPv4_FRAME_TYPE:
\r
694 /* Check it here. */
\r
697 /* Refuse the packet. */
\r
701 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
\r
703 const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);
\r
704 uint32_t ulDestinationIPAddress;
\r
706 /* Ensure that the incoming packet is not fragmented (only outgoing packets
\r
707 * can be fragmented) as these are the only handled IP frames currently. */
\r
708 if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U )
\r
712 /* HT: Might want to make the following configurable because
\r
713 * most IP messages have a standard length of 20 bytes */
\r
715 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
\r
716 * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
\r
717 if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F )
\r
722 ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
\r
723 /* Is the packet for this node? */
\r
724 if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
\r
725 /* Is it a broadcast address x.x.x.255 ? */
\r
726 ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&
\r
727 #if( ipconfigUSE_LLMNR == 1 )
\r
728 ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
\r
730 ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {
\r
731 FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );
\r
735 if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP )
\r
737 uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;
\r
739 if( ( xPortHasUDPSocket( port ) == pdFALSE )
\r
740 #if ipconfigUSE_LLMNR == 1
\r
741 && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )
\r
743 #if ipconfigUSE_NBNS == 1
\r
744 && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )
\r
746 #if ipconfigUSE_DNS == 1
\r
747 && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )
\r
750 /* Drop this packet, not for this device. */
\r
755 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
\r
758 /*-----------------------------------------------------------*/
\r
760 static BaseType_t prvNetworkInterfaceInput( void )
\r
762 NetworkBufferDescriptor_t *pxCurDescriptor;
\r
763 NetworkBufferDescriptor_t *pxNewDescriptor = NULL;
\r
764 BaseType_t xReceivedLength, xAccepted;
\r
765 __IO ETH_DMADescTypeDef *pxDMARxDescriptor;
\r
766 xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
767 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );
\r
768 uint8_t *pucBuffer;
\r
770 pxDMARxDescriptor = xETH.RxDesc;
\r
772 if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 )
\r
774 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
\r
775 xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;
\r
777 pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;
\r
779 /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */
\r
780 /* Chained Mode */
\r
781 /* Selects the next DMA Rx descriptor list for next buffer to read */
\r
782 xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;
\r
786 xReceivedLength = 0;
\r
789 /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */
\r
790 /* In order to make the code easier and faster, only packets in a single buffer
\r
791 will be accepted. This can be done by making the buffers large enough to
\r
792 hold a complete Ethernet packet (1536 bytes). */
\r
793 if( xReceivedLength > 0ul && xReceivedLength < ETH_RX_BUF_SIZE )
\r
795 if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT )
\r
797 /* Not an Ethernet frame-type or a checmsum error. */
\r
798 xAccepted = pdFALSE;
\r
802 /* See if this packet must be handled. */
\r
803 xAccepted = xMayAcceptPacket( pucBuffer );
\r
806 if( xAccepted != pdFALSE )
\r
808 /* The packet wil be accepted, but check first if a new Network Buffer can
\r
809 be obtained. If not, the packet will still be dropped. */
\r
810 pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );
\r
812 if( pxNewDescriptor == NULL )
\r
814 /* A new descriptor can not be allocated now. This packet will be dropped. */
\r
815 xAccepted = pdFALSE;
\r
818 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
820 /* Find out which Network Buffer was originally passed to the descriptor. */
\r
821 pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
\r
822 configASSERT( pxCurDescriptor != NULL );
\r
826 /* In this mode, the two descriptors are the same. */
\r
827 pxCurDescriptor = pxNewDescriptor;
\r
828 if( pxNewDescriptor != NULL )
\r
830 /* The packet is acepted and a new Network Buffer was created,
\r
831 copy data to the Network Bufffer. */
\r
832 memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );
\r
837 if( xAccepted != pdFALSE )
\r
839 pxCurDescriptor->xDataLength = xReceivedLength;
\r
840 xRxEvent.pvData = ( void * ) pxCurDescriptor;
\r
842 /* Pass the data to the TCP/IP task for processing. */
\r
843 if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )
\r
845 /* Could not send the descriptor into the TCP/IP stack, it
\r
846 must be released. */
\r
847 vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );
\r
848 iptraceETHERNET_RX_EVENT_LOST();
\r
852 iptraceNETWORK_INTERFACE_RECEIVE();
\r
856 /* Release descriptors to DMA */
\r
857 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )
\r
859 /* Set Buffer1 address pointer */
\r
860 if( pxNewDescriptor != NULL )
\r
862 pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;
\r
866 /* The packet was dropped and the same Network
\r
867 Buffer will be used to receive a new packet. */
\r
870 #endif /* ipconfigZERO_COPY_RX_DRIVER */
\r
872 /* Set Buffer1 size and Second Address Chained bit */
\r
873 pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
\r
874 pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
\r
876 /* Ensure completion of memory access */
\r
878 /* When Rx Buffer unavailable flag is set clear it and resume
\r
880 if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
\r
882 /* Clear RBUS ETHERNET DMA flag. */
\r
883 xETH.Instance->DMASR = ETH_DMASR_RBUS;
\r
885 /* Resume DMA reception. */
\r
886 xETH.Instance->DMARPDR = 0;
\r
890 return ( xReceivedLength > 0 );
\r
892 /*-----------------------------------------------------------*/
\r
895 BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue )
\r
897 uint16_t usPrevAddress = xETH.Init.PhyAddress;
\r
898 BaseType_t xResult;
\r
899 HAL_StatusTypeDef xHALResult;
\r
901 xETH.Init.PhyAddress = xAddress;
\r
902 xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue );
\r
903 xETH.Init.PhyAddress = usPrevAddress;
\r
905 if( xHALResult == HAL_OK )
\r
915 /*-----------------------------------------------------------*/
\r
917 BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue )
\r
919 uint16_t usPrevAddress = xETH.Init.PhyAddress;
\r
920 BaseType_t xResult;
\r
921 HAL_StatusTypeDef xHALResult;
\r
923 xETH.Init.PhyAddress = xAddress;
\r
924 xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue );
\r
925 xETH.Init.PhyAddress = usPrevAddress;
\r
927 if( xHALResult == HAL_OK )
\r
937 /*-----------------------------------------------------------*/
\r
941 BaseType_t xPhyCount;
\r
942 BaseType_t xPhyIndex;
\r
944 vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
\r
945 xPhyCount = xPhyDiscover( &xPhyObject );
\r
946 FreeRTOS_printf( ( "PHY count %ld\n", xPhyCount ) );
\r
947 for( xPhyIndex = 0; xPhyIndex < xPhyCount; xPhyIndex++ )
\r
949 FreeRTOS_printf( ( "PHY[%d] at address %d ( 0x%08X )\n",
\r
951 xPhyObject.ucPhyIndexes[ xPhyIndex ],
\r
952 xPhyObject.ulPhyIDs[ xPhyIndex ] ) );
\r
958 void vMACBProbePhy( void )
\r
960 vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
\r
961 xPhyDiscover( &xPhyObject );
\r
962 xPhyConfigure( &xPhyObject, &xPHYProperties );
\r
964 /*-----------------------------------------------------------*/
\r
966 static void prvEthernetUpdateConfig( BaseType_t xForce )
\r
968 FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
\r
969 xPhyObject.ulLinkStatusMask,
\r
972 if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
\r
974 /* Restart the auto-negotiation. */
\r
975 if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
\r
977 xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
\r
979 /* Configure the MAC with the Duplex Mode fixed by the
\r
980 auto-negotiation process. */
\r
981 if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
\r
983 xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
\r
987 xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
\r
990 /* Configure the MAC with the speed fixed by the
\r
991 auto-negotiation process. */
\r
992 if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
\r
994 xETH.Init.Speed = ETH_SPEED_10M;
\r
998 xETH.Init.Speed = ETH_SPEED_100M;
\r
1001 else /* AutoNegotiation Disable */
\r
1003 /* Check parameters */
\r
1004 assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
\r
1005 assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
\r
1007 if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX )
\r
1009 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;
\r
1013 xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;
\r
1016 if( xETH.Init.Speed == ETH_SPEED_10M )
\r
1018 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;
\r
1022 xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;
\r
1025 xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;
\r
1027 /* Use predefined (fixed) configuration. */
\r
1028 xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
\r
1031 /* ETHERNET MAC Re-Configuration */
\r
1032 HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);
\r
1034 /* Restart MAC interface */
\r
1035 HAL_ETH_Start( &xETH);
\r
1039 /* Stop MAC interface */
\r
1040 HAL_ETH_Stop( &xETH );
\r
1043 /*-----------------------------------------------------------*/
\r
1045 BaseType_t xGetPhyLinkStatus( void )
\r
1047 BaseType_t xReturn;
\r
1049 if( xPhyObject.ulLinkStatusMask != 0 )
\r
1060 /*-----------------------------------------------------------*/
\r
1062 /* Uncomment this in case BufferAllocation_1.c is used. */
\r
1065 #define niBUFFER_1_PACKET_SIZE 1536
\r
1067 static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
\r
1069 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
\r
1072 uint8_t *ucRAMBuffer = ucNetworkPackets;
\r
1075 for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
\r
1077 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
\r
1078 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
\r
1079 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
\r
1083 /*-----------------------------------------------------------*/
\r
1085 static void prvEMACHandlerTask( void *pvParameters )
\r
1087 UBaseType_t uxLastMinBufferCount = 0;
\r
1088 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1089 UBaseType_t uxLastMinQueueSpace = 0;
\r
1091 UBaseType_t uxCurrentCount;
\r
1092 BaseType_t xResult;
\r
1093 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
\r
1095 /* Remove compiler warnings about unused parameters. */
\r
1096 ( void ) pvParameters;
\r
1101 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
1102 if( uxLastMinBufferCount != uxCurrentCount )
\r
1104 /* The logging produced below may be helpful
\r
1105 while tuning +TCP: see how many buffers are in use. */
\r
1106 uxLastMinBufferCount = uxCurrentCount;
\r
1107 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
1108 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
1111 if( xTXDescriptorSemaphore != NULL )
\r
1113 static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
\r
1115 uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );
\r
1116 if( uxLowestSemCount > uxCurrentCount )
\r
1118 uxLowestSemCount = uxCurrentCount;
\r
1119 FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );
\r
1124 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1126 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
1127 if( uxLastMinQueueSpace != uxCurrentCount )
\r
1129 /* The logging produced below may be helpful
\r
1130 while tuning +TCP: see how many buffers are in use. */
\r
1131 uxLastMinQueueSpace = uxCurrentCount;
\r
1132 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
1135 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
1137 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
1139 /* No events to process now, wait for the next. */
\r
1140 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
\r
1143 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
1145 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
1147 xResult = prvNetworkInterfaceInput();
\r
1150 while( prvNetworkInterfaceInput() > 0 )
\r
1156 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
1158 /* Code to release TX buffers if zero-copy is used. */
\r
1159 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
1160 /* Check if DMA packets have been delivered. */
\r
1161 vClearTXBuffers();
\r
1164 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
1166 /* Future extension: logging about errors that occurred. */
\r
1167 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
1169 if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
\r
1171 /* Something has changed to a Link Status, need re-check. */
\r
1172 prvEthernetUpdateConfig( pdFALSE );
\r
1176 /*-----------------------------------------------------------*/
\r
1178 void ETH_IRQHandler( void )
\r
1180 HAL_ETH_IRQHandler( &xETH );
\r