mirror of
https://github.com/FreeRTOS/FreeRTOS-Plus-TCP
synced 2025-10-22 07:51:40 +08:00
1141 lines
41 KiB
C
1141 lines
41 KiB
C
/*
|
|
* Some constants, hardware definitions and comments taken from ST's HAL driver
|
|
* library, COPYRIGHT(c) 2015 STMicroelectronics.
|
|
*/
|
|
|
|
/*
|
|
* FreeRTOS+TCP V2.3.2
|
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* http://aws.amazon.com/freertos
|
|
* http://www.FreeRTOS.org
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "semphr.h"
|
|
|
|
/* FreeRTOS+TCP includes. */
|
|
#include "FreeRTOS_IP.h"
|
|
#include "FreeRTOS_Sockets.h"
|
|
#include "FreeRTOS_IP_Private.h"
|
|
#include "FreeRTOS_DNS.h"
|
|
#include "FreeRTOS_Routing.h"
|
|
#include "NetworkBufferManagement.h"
|
|
#include "NetworkInterface.h"
|
|
|
|
#include "phyHandling.h"
|
|
|
|
/* ST includes. */
|
|
#include "stm32h7xx_hal.h"
|
|
|
|
#ifndef STM32Hxx_HAL_ETH_H
|
|
|
|
/*
|
|
* The ST HAL library provides stm32h7xx_hal_eth.{c,h}.
|
|
* This FreeRTOS+TCP driver renamed these files to stm32hxx_hal_eth.{c,h}
|
|
* by removing the '7'.
|
|
* Please make sure that "portable/NetworkInterface/STM32Hxx" is included
|
|
* in the include paths earlier than "STM32H7xx_HAL_Driver/Inc".
|
|
* and also make sure that you have defined 'HAL_ETH_MODULE_ENABLED'
|
|
* in your copy of "stm32h7xx_hal_conf".
|
|
*/
|
|
#error stm32hxx_hal_eth.h is possibly not included
|
|
#endif
|
|
|
|
/* Interrupt events to process: reception, transmission and error handling. */
|
|
#define EMAC_IF_RX_EVENT 1UL
|
|
#define EMAC_IF_TX_EVENT 2UL
|
|
#define EMAC_IF_ERR_EVENT 4UL
|
|
|
|
|
|
#ifndef niEMAC_HANDLER_TASK_NAME
|
|
#define niEMAC_HANDLER_TASK_NAME "EMAC-task"
|
|
#endif
|
|
|
|
#ifndef niEMAC_HANDLER_TASK_STACK_SIZE
|
|
#define niEMAC_HANDLER_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
|
|
#endif
|
|
|
|
#ifndef niEMAC_HANDLER_TASK_PRIORITY
|
|
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
|
|
#endif
|
|
|
|
|
|
/* Bit map of outstanding ETH interrupt events for processing. */
|
|
static volatile uint32_t ulISREvents;
|
|
|
|
typedef enum
|
|
{
|
|
eMACInit, /* Must initialise MAC. */
|
|
eMACPass, /* Initialisation was successful. */
|
|
eMACFailed, /* Initialisation failed. */
|
|
} eMAC_INIT_STATUS_TYPE;
|
|
|
|
static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
|
|
|
|
/* xTXDescriptorSemaphore is shared with stm32h7xx_hal_eth.c. */
|
|
SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
|
|
|
|
/* Both the IP-task and the EMAC task use the TX channel. Use
|
|
* a mutex to protect it against synchronous access by both tasks. */
|
|
static SemaphoreHandle_t xTransmissionMutex;
|
|
|
|
/* Global Ethernet handle */
|
|
static ETH_HandleTypeDef xEthHandle;
|
|
static ETH_TxPacketConfig xTxConfig;
|
|
|
|
static NetworkInterface_t * pxMyInterface = NULL;
|
|
|
|
/*
|
|
* About the section ".ethernet_data" : the DMA wants the descriptors and buffers allocated in the
|
|
* RAM3 memory, which can be added to the .LD file as follows::
|
|
*
|
|
* RAM3 (xrw) : ORIGIN = 0x24040000, LENGTH = 0x8000
|
|
*
|
|
* .ethernet_data :
|
|
* {
|
|
* PROVIDE_HIDDEN (__ethernet_data_start = .);
|
|
* KEEP (*(SORT(.ethernet_data.*)))
|
|
* KEEP (*(.ethernet_data*))
|
|
* PROVIDE_HIDDEN (__ethernet_data_end = .);
|
|
* } >RAM3
|
|
*
|
|
*/
|
|
/* Ethernet Rx DMA Descriptors */
|
|
ETH_DMADescTypeDef DMARxDscrTab[ ETH_RX_DESC_CNT ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
|
|
|
|
/* Ethernet Receive Buffer */
|
|
#if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
|
|
uint8_t Rx_Buff[ ETH_RX_DESC_CNT ][ ETH_RX_BUF_SIZE ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
|
|
#endif
|
|
|
|
/* Ethernet Tx DMA Descriptors */
|
|
ETH_DMADescTypeDef DMATxDscrTab[ ETH_TX_DESC_CNT ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
|
|
|
|
/* Ethernet Transmit Buffer */
|
|
#if ( ipconfigZERO_COPY_TX_DRIVER == 0 )
|
|
uint8_t Tx_Buff[ ETH_TX_DESC_CNT ][ ETH_TX_BUF_SIZE ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
|
|
#endif
|
|
|
|
/* This function binds PHY IO functions, then inits and configures */
|
|
static void prvMACBProbePhy( void );
|
|
|
|
/* Force a negotiation with the Switch or Router and wait for LS. */
|
|
static void prvEthernetUpdateConfig( BaseType_t xForce );
|
|
|
|
/* Holds the handle of the task used as a deferred interrupt processor. The
|
|
* handle is used so direct notifications can be sent to the task for all EMAC/DMA
|
|
* related interrupts. */
|
|
static TaskHandle_t xEMACTaskHandle = NULL;
|
|
|
|
/*
|
|
* A deferred interrupt handler task that processes
|
|
*/
|
|
static void prvEMACHandlerTask( void * pvParameters );
|
|
|
|
/*
|
|
* See if there is a new packet and forward it to the IP-task.
|
|
*/
|
|
static BaseType_t prvNetworkInterfaceInput( void );
|
|
|
|
/* Private PHY IO functions and properties */
|
|
static int32_t ETH_PHY_IO_ReadReg( uint32_t DevAddr,
|
|
uint32_t RegAddr,
|
|
uint32_t * pRegVal );
|
|
static int32_t ETH_PHY_IO_WriteReg( uint32_t DevAddr,
|
|
uint32_t RegAddr,
|
|
uint32_t RegVal );
|
|
|
|
static void vClearOptionBit( volatile uint32_t * pulValue,
|
|
uint32_t ulValue );
|
|
|
|
#if ( ipconfigHAS_PRINTF != 0 )
|
|
static size_t uxGetOwnCount( ETH_HandleTypeDef * heth );
|
|
#endif
|
|
|
|
/* FreeRTOS+TCP/multi :
|
|
* Each network device has 3 access functions:
|
|
* - Initialise the device
|
|
* - Output a network packet
|
|
* - Return the PHY Link-Status (LS)
|
|
* They can be defined as static because the function addresses
|
|
* addresses will be stored in struct NetworkInterface_t. */
|
|
|
|
static BaseType_t xSTM32H_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface );
|
|
|
|
static BaseType_t xSTM32H_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
|
|
NetworkBufferDescriptor_t * const pxBuffer,
|
|
BaseType_t xReleaseAfterSend );
|
|
|
|
static BaseType_t xSTM32H_GetPhyLinkStatus( NetworkInterface_t * pxInterface );
|
|
|
|
NetworkInterface_t * pxSTM32H_FillInterfaceDescriptor( BaseType_t xEMACIndex,
|
|
NetworkInterface_t * pxInterface );
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static EthernetPhy_t xPhyObject;
|
|
/* For local use only: describe the PHY's properties: */
|
|
const PhyProperties_t xPHYProperties =
|
|
{
|
|
.ucSpeed = PHY_SPEED_AUTO,
|
|
.ucDuplex = PHY_DUPLEX_AUTO,
|
|
.ucMDI_X = PHY_MDIX_DIRECT
|
|
};
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvMACAddressConfig( ETH_HandleTypeDef * heth,
|
|
uint32_t ulIndex,
|
|
const uint8_t * Addr )
|
|
{
|
|
uint32_t ulTempReg;
|
|
uint32_t ulETH_MAC_ADDR_HBASE = ( uint32_t ) &( heth->Instance->MACA0HR );
|
|
uint32_t ulETH_MAC_ADDR_LBASE = ( uint32_t ) &( heth->Instance->MACA0LR );
|
|
|
|
/* ETH_MAC_ADDRESS0 reserved for the primary MAC-address. */
|
|
configASSERT( ulIndex >= ETH_MAC_ADDRESS1 );
|
|
|
|
/* STM32Hxx devices support 4 MAC address registers
|
|
* (ETH_MAC_ADDRESS0 - ETH_MAC_ADDRESS3), make sure ulIndex is not
|
|
* more than that. */
|
|
configASSERT( ulIndex <= ETH_MAC_ADDRESS3 );
|
|
|
|
/* Calculate the selected MAC address high register. */
|
|
ulTempReg = 0xBF000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];
|
|
|
|
/* Load the selected MAC address high register. */
|
|
( *( __IO uint32_t * ) ( ( uint32_t ) ( ulETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;
|
|
|
|
/* Calculate the selected MAC address low register. */
|
|
ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];
|
|
|
|
/* Load the selected MAC address low register */
|
|
( *( __IO uint32_t * ) ( ( uint32_t ) ( ulETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
/*******************************************************************************
|
|
* Network Interface API Functions
|
|
*******************************************************************************/
|
|
|
|
static uint8_t * pucGetRXBuffer( size_t uxSize )
|
|
{
|
|
TickType_t uxBlockTimeTicks = ipMS_TO_MIN_TICKS( 10U );
|
|
NetworkBufferDescriptor_t * pxBufferDescriptor;
|
|
uint8_t * pucReturn = NULL;
|
|
|
|
pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( uxSize, uxBlockTimeTicks );
|
|
|
|
if( pxBufferDescriptor != NULL )
|
|
{
|
|
pucReturn = pxBufferDescriptor->pucEthernetBuffer;
|
|
}
|
|
|
|
return pucReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t xSTM32H_NetworkInterfaceInitialise( NetworkInterface_t * pxInterface )
|
|
{
|
|
BaseType_t xResult;
|
|
NetworkEndPoint_t * pxEndPoint;
|
|
HAL_StatusTypeDef xHalEthInitStatus;
|
|
size_t uxIndex = 0;
|
|
BaseType_t xMACEntry = ETH_MAC_ADDRESS1; /* ETH_MAC_ADDRESS0 reserved for the primary MAC-address. */
|
|
|
|
if( xMacInitStatus == eMACInit )
|
|
{
|
|
pxMyInterface = pxInterface;
|
|
|
|
pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
|
|
configASSERT( pxEndPoint != NULL );
|
|
|
|
/*
|
|
* Initialize ETH Handler
|
|
* It assumes that Ethernet GPIO and clock configuration
|
|
* are already done in the ETH_MspInit()
|
|
*/
|
|
xEthHandle.Instance = ETH;
|
|
xEthHandle.Init.MACAddr = ( uint8_t * ) pxEndPoint->xMACAddress.ucBytes;
|
|
xEthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
|
|
xEthHandle.Init.TxDesc = DMATxDscrTab;
|
|
xEthHandle.Init.RxDesc = DMARxDscrTab;
|
|
xEthHandle.Init.RxBuffLen = ( ETH_RX_BUF_SIZE - ipBUFFER_PADDING ) & ~( ( uint32_t ) 3U );
|
|
|
|
/* Make sure that all unused fields are cleared. */
|
|
memset( &( DMATxDscrTab ), '\0', sizeof( DMATxDscrTab ) );
|
|
memset( &( DMARxDscrTab ), '\0', sizeof( DMARxDscrTab ) );
|
|
|
|
xHalEthInitStatus = HAL_ETH_Init( &( xEthHandle ) );
|
|
|
|
/* Only for inspection by debugger. */
|
|
( void ) xHalEthInitStatus;
|
|
|
|
/* Configuration for HAL_ETH_Transmit(_IT). */
|
|
memset( &( xTxConfig ), 0, sizeof( ETH_TxPacketConfig ) );
|
|
xTxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CRCPAD;
|
|
|
|
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
|
|
{
|
|
/*xTxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; */
|
|
xTxConfig.Attributes |= ETH_TX_PACKETS_FEATURES_CSUM;
|
|
xTxConfig.ChecksumCtrl = ETH_DMATXNDESCRF_CIC_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
|
|
}
|
|
#else
|
|
{
|
|
xTxConfig.ChecksumCtrl = ETH_CHECKSUM_DISABLE;
|
|
}
|
|
#endif
|
|
xTxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
|
|
|
|
/* This counting semaphore will count the number of free TX DMA descriptors. */
|
|
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TX_DESC_CNT, ( UBaseType_t ) ETH_TX_DESC_CNT );
|
|
configASSERT( xTXDescriptorSemaphore );
|
|
|
|
xTransmissionMutex = xSemaphoreCreateMutex();
|
|
configASSERT( xTransmissionMutex );
|
|
|
|
/* Assign Rx memory buffers to a DMA Rx descriptor */
|
|
for( uxIndex = 0; uxIndex < ETH_RX_DESC_CNT; uxIndex++ )
|
|
{
|
|
uint8_t * pucBuffer;
|
|
|
|
#if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
|
|
{
|
|
pucBuffer = pucGetRXBuffer( ETH_RX_BUF_SIZE );
|
|
configASSERT( pucBuffer != NULL );
|
|
}
|
|
#else
|
|
{
|
|
pucBuffer = Rx_Buff[ uxIndex ];
|
|
}
|
|
#endif
|
|
|
|
HAL_ETH_DescAssignMemory( &( xEthHandle ), uxIndex, pucBuffer, NULL );
|
|
}
|
|
|
|
#if ( ipconfigUSE_MDNS == 1 )
|
|
{
|
|
/* Program the MDNS address. */
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xMDNS_MacAdress.ucBytes );
|
|
xMACEntry += 8;
|
|
}
|
|
#endif
|
|
#if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
|
|
{
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xMDNS_MACAdressIPv6.ucBytes );
|
|
xMACEntry += 8;
|
|
}
|
|
#endif
|
|
#if ( ipconfigUSE_LLMNR == 1 )
|
|
{
|
|
/* Program the LLMNR address. */
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xLLMNR_MacAdress.ucBytes );
|
|
xMACEntry += 8;
|
|
}
|
|
#endif
|
|
#if ( ( ipconfigUSE_LLMNR == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
|
|
{
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, ( uint8_t * ) xLLMNR_MacAdressIPv6.ucBytes );
|
|
xMACEntry += 8;
|
|
}
|
|
#endif
|
|
|
|
{
|
|
/* The EMAC address of the first end-point has been registered in HAL_ETH_Init(). */
|
|
for( ;
|
|
pxEndPoint != NULL;
|
|
pxEndPoint = FreeRTOS_NextEndPoint( pxMyInterface, pxEndPoint ) )
|
|
{
|
|
switch( pxEndPoint->bits.bIPv6 )
|
|
{
|
|
#if ( ipconfigUSE_IPv4 != 0 )
|
|
case pdFALSE_UNSIGNED:
|
|
|
|
if( xEthHandle.Init.MACAddr != ( uint8_t * ) pxEndPoint->xMACAddress.ucBytes )
|
|
{
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, pxEndPoint->xMACAddress.ucBytes );
|
|
xMACEntry += 8;
|
|
}
|
|
break;
|
|
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
|
|
|
|
#if ( ipconfigUSE_IPv6 != 0 )
|
|
case pdTRUE_UNSIGNED:
|
|
{
|
|
uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0xff, 0, 0, 0 };
|
|
|
|
ucMACAddress[ 3 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 13 ];
|
|
ucMACAddress[ 4 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 14 ];
|
|
ucMACAddress[ 5 ] = pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 15 ];
|
|
|
|
/* Allow traffic destined to Solicited-Node multicast address of this endpoint
|
|
* for Duplicate Address Detection (DAD) */
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, ucMACAddress );
|
|
xMACEntry += 8;
|
|
}
|
|
break;
|
|
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
|
|
|
|
default:
|
|
/* MISRA 16.4 Compliance */
|
|
break;
|
|
}
|
|
|
|
if( xMACEntry > ( BaseType_t ) ETH_MAC_ADDRESS3 )
|
|
{
|
|
/* No more locations available. */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if ( ipconfigUSE_IPv6 != 0 )
|
|
{
|
|
if( xMACEntry <= ( BaseType_t ) ETH_MAC_ADDRESS3 )
|
|
{
|
|
/* Allow traffic destined to IPv6 all nodes multicast MAC 33:33:00:00:00:01 */
|
|
uint8_t ucMACAddress[ 6 ] = { 0x33, 0x33, 0, 0, 0, 0x01 };
|
|
|
|
prvMACAddressConfig( &xEthHandle, xMACEntry, ucMACAddress );
|
|
xMACEntry += 8;
|
|
}
|
|
}
|
|
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
|
|
|
|
/* Initialize the MACB and set all PHY properties */
|
|
prvMACBProbePhy();
|
|
|
|
/* Force a negotiation with the Switch or Router and wait for LS. */
|
|
prvEthernetUpdateConfig( pdTRUE );
|
|
|
|
/* The deferred interrupt handler task is created at the highest
|
|
* possible priority to ensure the interrupt handler can return directly
|
|
* to it. The task's handle is stored in xEMACTaskHandle so interrupts can
|
|
* notify the task when there is something to process. */
|
|
if( xTaskCreate( prvEMACHandlerTask, niEMAC_HANDLER_TASK_NAME, niEMAC_HANDLER_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &( xEMACTaskHandle ) ) == pdPASS )
|
|
{
|
|
/* The task was created successfully. */
|
|
xMacInitStatus = eMACPass;
|
|
}
|
|
else
|
|
{
|
|
xMacInitStatus = eMACFailed;
|
|
}
|
|
} /* ( xMacInitStatus == eMACInit ) */
|
|
|
|
if( xMacInitStatus != eMACPass )
|
|
{
|
|
/* EMAC initialisation failed, return pdFAIL. */
|
|
xResult = pdFAIL;
|
|
}
|
|
else
|
|
{
|
|
if( xPhyObject.ulLinkStatusMask != 0uL )
|
|
{
|
|
xResult = pdPASS;
|
|
FreeRTOS_printf( ( "Link Status is high\n" ) );
|
|
}
|
|
else
|
|
{
|
|
/* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
|
|
* and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
|
|
xResult = pdFAIL;
|
|
}
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t xSTM32H_GetPhyLinkStatus( NetworkInterface_t * pxInterface )
|
|
{
|
|
BaseType_t xReturn;
|
|
|
|
if( xPhyObject.ulLinkStatusMask != 0U )
|
|
{
|
|
xReturn = pdPASS;
|
|
}
|
|
else
|
|
{
|
|
xReturn = pdFAIL;
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
|
|
|
|
/* Do not call the following function directly. It is there for downward compatibility.
|
|
* The function FreeRTOS_IPInit() will call it to initialice the interface and end-point
|
|
* objects. See the description in FreeRTOS_Routing.h. */
|
|
NetworkInterface_t * pxFillInterfaceDescriptor( BaseType_t xEMACIndex,
|
|
NetworkInterface_t * pxInterface )
|
|
{
|
|
return pxSTM32H_FillInterfaceDescriptor( xEMACIndex, pxInterface );
|
|
}
|
|
|
|
#endif
|
|
/*-----------------------------------------------------------*/
|
|
|
|
NetworkInterface_t * pxSTM32H_FillInterfaceDescriptor( BaseType_t xEMACIndex,
|
|
NetworkInterface_t * pxInterface )
|
|
{
|
|
static char pcName[ 17 ];
|
|
|
|
/* This function pxSTM32Hxx_FillInterfaceDescriptor() adds a network-interface.
|
|
* Make sure that the object pointed to by 'pxInterface'
|
|
* is declared static or global, and that it will remain to exist. */
|
|
|
|
snprintf( pcName, sizeof( pcName ), "eth%u", ( unsigned ) xEMACIndex );
|
|
|
|
memset( pxInterface, '\0', sizeof( *pxInterface ) );
|
|
pxInterface->pcName = pcName; /* Just for logging, debugging. */
|
|
pxInterface->pvArgument = ( void * ) xEMACIndex; /* Has only meaning for the driver functions. */
|
|
pxInterface->pfInitialise = xSTM32H_NetworkInterfaceInitialise;
|
|
pxInterface->pfOutput = xSTM32H_NetworkInterfaceOutput;
|
|
pxInterface->pfGetPhyLinkStatus = xSTM32H_GetPhyLinkStatus;
|
|
|
|
FreeRTOS_AddNetworkInterface( pxInterface );
|
|
|
|
return pxInterface;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t xSTM32H_NetworkInterfaceOutput( NetworkInterface_t * pxInterface,
|
|
NetworkBufferDescriptor_t * const pxBuffer,
|
|
BaseType_t xReleaseAfterSend )
|
|
{
|
|
BaseType_t xResult = pdFAIL;
|
|
TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 100U );
|
|
uint8_t * pucTXBuffer;
|
|
|
|
if( xSTM32H_GetPhyLinkStatus( pxInterface ) == pdPASS )
|
|
{
|
|
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
|
/* Zero-copy method, pass the buffer. */
|
|
pucTXBuffer = pxBuffer->pucEthernetBuffer;
|
|
|
|
/* As the buffer is passed to the driver, it must exist.
|
|
* The library takes care of this. */
|
|
configASSERT( xReleaseAfterSend != pdFALSE );
|
|
#else
|
|
pucTXBuffer = Tx_Buff[ xEthHandle.TxDescList.CurTxDesc ];
|
|
/* The copy method, left here for educational purposes. */
|
|
configASSERT( pxBuffer->xDataLength <= sizeof( Tx_Buff[ 0 ] ) );
|
|
#endif
|
|
|
|
ETH_BufferTypeDef xTransmitBuffer =
|
|
{
|
|
.buffer = pucTXBuffer,
|
|
.len = pxBuffer->xDataLength,
|
|
.next = NULL /* FreeRTOS+TCP does not use linked buffers. */
|
|
};
|
|
/* This is the total length, which is equal to the buffer. */
|
|
xTxConfig.Length = pxBuffer->xDataLength;
|
|
xTxConfig.TxBuffer = &( xTransmitBuffer );
|
|
|
|
/* This counting semaphore counts the number of free TX DMA descriptors. */
|
|
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
|
|
{
|
|
/* If the logging routine is using the network, the following message
|
|
* may cause a new error message. */
|
|
FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
|
|
}
|
|
else
|
|
{
|
|
/* Memory barrier: Make sure that the data written to the packet buffer got written. */
|
|
__DSB();
|
|
|
|
/* Get exclusive accces to the TX process.
|
|
* Both the IP-task and the EMAC task will work on the TX process. */
|
|
if( xSemaphoreTake( xTransmissionMutex, xBlockTimeTicks ) != pdFAIL )
|
|
{
|
|
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
|
{
|
|
/* Do not release the buffer. */
|
|
xReleaseAfterSend = pdFALSE;
|
|
}
|
|
#else
|
|
{
|
|
memcpy( pucTXBuffer, pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
|
|
|
|
/* A memory barrier to make sure that the outgoing packets has been written
|
|
* to the physical memory. */
|
|
__DSB();
|
|
}
|
|
#endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
|
|
|
|
if( HAL_ETH_Transmit_IT( &( xEthHandle ), &( xTxConfig ) ) == HAL_OK )
|
|
{
|
|
xResult = pdPASS;
|
|
}
|
|
|
|
/* And release the mutex. */
|
|
xSemaphoreGive( xTransmissionMutex );
|
|
}
|
|
|
|
/* Call the standard trace macro to log the send event. */
|
|
iptraceNETWORK_INTERFACE_TRANSMIT();
|
|
}
|
|
}
|
|
|
|
if( xReleaseAfterSend != pdFALSE )
|
|
{
|
|
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
|
}
|
|
|
|
return xResult;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/*******************************************************************************
|
|
* END Network Interface API Functions
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* Network Interface Static Functions
|
|
*******************************************************************************/
|
|
|
|
static void prvMACBProbePhy( void )
|
|
{
|
|
/* Bind the write and read access functions. */
|
|
vPhyInitialise( &( xPhyObject ),
|
|
( xApplicationPhyReadHook_t ) ETH_PHY_IO_ReadReg,
|
|
( xApplicationPhyWriteHook_t ) ETH_PHY_IO_WriteReg );
|
|
/* Poll the bus for all connected PHY's. */
|
|
xPhyDiscover( &( xPhyObject ) );
|
|
/* Configure them using the properties provided. */
|
|
xPhyConfigure( &( xPhyObject ), &( xPHYProperties ) );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvEthernetUpdateConfig( BaseType_t xForce )
|
|
{
|
|
ETH_MACConfigTypeDef MACConf;
|
|
uint32_t speed = 0, duplex = 0;
|
|
|
|
FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
|
|
xPhyObject.ulLinkStatusMask,
|
|
( int ) xForce ) );
|
|
|
|
if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
|
|
{
|
|
/* Restart the auto-negotiation. */
|
|
xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &( xPhyObject ) ) );
|
|
|
|
/* Configure the MAC with the Duplex Mode fixed by the
|
|
* auto-negotiation process. */
|
|
if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
|
|
{
|
|
duplex = ETH_FULLDUPLEX_MODE;
|
|
}
|
|
else
|
|
{
|
|
duplex = ETH_HALFDUPLEX_MODE;
|
|
}
|
|
|
|
/* Configure the MAC with the speed fixed by the
|
|
* auto-negotiation process. */
|
|
if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
|
|
{
|
|
speed = ETH_SPEED_10M;
|
|
}
|
|
else
|
|
{
|
|
speed = ETH_SPEED_100M;
|
|
}
|
|
|
|
/* Get MAC and configure it */
|
|
HAL_ETH_GetMACConfig( &( xEthHandle ), &( MACConf ) );
|
|
MACConf.DuplexMode = duplex;
|
|
MACConf.Speed = speed;
|
|
HAL_ETH_SetMACConfig( &( xEthHandle ), &( MACConf ) );
|
|
#if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
|
|
{
|
|
MACConf.ChecksumOffload = ENABLE;
|
|
}
|
|
#else
|
|
{
|
|
MACConf.ChecksumOffload = DISABLE;
|
|
}
|
|
#endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 ) */
|
|
|
|
/* Restart MAC interface */
|
|
HAL_ETH_Start_IT( &( xEthHandle ) );
|
|
}
|
|
else
|
|
{
|
|
/* Stop MAC interface */
|
|
HAL_ETH_Stop_IT( &( xEthHandle ) );
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static BaseType_t prvNetworkInterfaceInput( void )
|
|
{
|
|
BaseType_t xReturn = 0;
|
|
|
|
/* For as long as a packet is immediately available. */
|
|
for( ; ; )
|
|
{
|
|
NetworkBufferDescriptor_t * pxBufferDescriptor;
|
|
NetworkBufferDescriptor_t * pxReceivedBuffer = NULL;
|
|
ETH_BufferTypeDef data_buffer;
|
|
size_t uxDataLength;
|
|
size_t uxLength;
|
|
|
|
uxDataLength = HAL_ETH_GetRxData( &( xEthHandle ), &( data_buffer ) );
|
|
|
|
if( uxDataLength == 0U )
|
|
{
|
|
/* No more packets received. */
|
|
break;
|
|
}
|
|
|
|
xReturn++;
|
|
|
|
#if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
|
|
{
|
|
/* Reserve the maximum length for the next reception. */
|
|
uxLength = ETH_RX_BUF_SIZE;
|
|
|
|
if( data_buffer.buffer != NULL )
|
|
{
|
|
pxReceivedBuffer = pxPacketBuffer_to_NetworkBuffer( data_buffer.buffer );
|
|
#if ( ipconfigTCP_IP_SANITY != 0 )
|
|
{
|
|
configASSERT( bIsValidNetworkDescriptor( pxReceivedBuffer ) != 0 );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if( pxReceivedBuffer == NULL )
|
|
{
|
|
FreeRTOS_printf( ( "Strange: no descriptor received\n" ) );
|
|
}
|
|
}
|
|
#else /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
|
|
{
|
|
/* Reserve the length of the packet that was just received. */
|
|
uxLength = uxDataLength;
|
|
}
|
|
#endif /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
|
|
|
|
pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( uxLength, 0u );
|
|
|
|
if( pxBufferDescriptor == NULL )
|
|
{
|
|
/* The event was lost because a network buffer was not available.
|
|
* Call the standard trace macro to log the occurrence. */
|
|
iptraceETHERNET_RX_EVENT_LOST();
|
|
}
|
|
|
|
#if ( ipconfigZERO_COPY_RX_DRIVER != 0 )
|
|
{
|
|
if( pxBufferDescriptor == NULL )
|
|
{
|
|
/* Can not receive this packet. Buffer will be re-used. */
|
|
pxReceivedBuffer = NULL;
|
|
}
|
|
else if( pxReceivedBuffer != NULL )
|
|
{
|
|
pxReceivedBuffer->xDataLength = uxDataLength;
|
|
}
|
|
else
|
|
{
|
|
/* Allocating a new buffer failed. */
|
|
}
|
|
}
|
|
#else /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
|
|
{
|
|
if( pxBufferDescriptor != NULL )
|
|
{
|
|
pxReceivedBuffer = pxBufferDescriptor;
|
|
/* The copy method. */
|
|
memcpy( pxReceivedBuffer->pucEthernetBuffer, data_buffer.buffer, uxDataLength );
|
|
pxReceivedBuffer->xDataLength = uxDataLength;
|
|
/* Make sure that the descriptor isn't used any more. */
|
|
pxBufferDescriptor = NULL;
|
|
}
|
|
}
|
|
#endif /* if ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
|
|
|
|
{
|
|
uint8_t * pucBuffer = NULL;
|
|
|
|
if( pxBufferDescriptor != NULL )
|
|
{
|
|
pucBuffer = pxBufferDescriptor->pucEthernetBuffer;
|
|
}
|
|
|
|
/* Assign an RX buffer to the descriptor, so that
|
|
* a next packet can be received. */
|
|
HAL_ETH_BuildRxDescriptors( &( xEthHandle ), pucBuffer );
|
|
}
|
|
|
|
/* See if the data contained in the received Ethernet frame needs
|
|
* to be processed. NOTE! It is preferable to do this in
|
|
* the interrupt service routine itself, which would remove the need
|
|
* to unblock this task for packets that don't need processing. */
|
|
|
|
if( pxReceivedBuffer != NULL )
|
|
{
|
|
BaseType_t xDoRelease = pdFALSE;
|
|
|
|
if( eConsiderFrameForProcessing( pxReceivedBuffer->pucEthernetBuffer ) != eProcessBuffer )
|
|
{
|
|
/* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */
|
|
xDoRelease = pdTRUE;
|
|
}
|
|
else
|
|
{
|
|
/* The event about to be sent to the TCP/IP is an Rx event.
|
|
* pvData is used to point to the network buffer descriptor that
|
|
* now references the received data. */
|
|
|
|
IPStackEvent_t xRxEvent =
|
|
{
|
|
.eEventType = eNetworkRxEvent,
|
|
.pvData = ( void * ) pxReceivedBuffer
|
|
};
|
|
|
|
pxReceivedBuffer->pxInterface = pxMyInterface;
|
|
pxReceivedBuffer->pxEndPoint = FreeRTOS_MatchingEndpoint( pxMyInterface, pxReceivedBuffer->pucEthernetBuffer );
|
|
|
|
/* Send the data to the TCP/IP stack. */
|
|
if( xSendEventStructToIPTask( &( xRxEvent ), 0 ) != pdFALSE )
|
|
{
|
|
/* The message was successfully sent to the TCP/IP stack.
|
|
* Call the standard trace macro to log the occurrence. */
|
|
iptraceNETWORK_INTERFACE_RECEIVE();
|
|
}
|
|
else
|
|
{
|
|
xDoRelease = pdTRUE;
|
|
|
|
/* The buffer could not be sent to the IP task so the buffer
|
|
* must be released. */
|
|
|
|
/* Make a call to the standard trace macro to log the
|
|
* occurrence. */
|
|
iptraceETHERNET_RX_EVENT_LOST();
|
|
}
|
|
}
|
|
|
|
if( xDoRelease != pdFALSE )
|
|
{
|
|
vReleaseNetworkBufferAndDescriptor( pxReceivedBuffer );
|
|
}
|
|
}
|
|
}
|
|
|
|
return xReturn;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/*******************************************************************************
|
|
* END Network Interface Static Functions
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* PHY IO Functions
|
|
*******************************************************************************/
|
|
|
|
/**
|
|
* @brief Read a PHY register through the MDIO interface.
|
|
* @param DevAddr: PHY port address
|
|
* @param RegAddr: PHY register address
|
|
* @param pRegVal: pointer to hold the register value
|
|
* @retval 0 if OK -1 if Error
|
|
*/
|
|
static int32_t ETH_PHY_IO_ReadReg( uint32_t ulDevAddr,
|
|
uint32_t ulRegAddr,
|
|
uint32_t * pulRegVal )
|
|
{
|
|
int32_t iResult = -1;
|
|
|
|
if( HAL_ETH_ReadPHYRegister( &( xEthHandle ), ulDevAddr, ulRegAddr, pulRegVal ) == HAL_OK )
|
|
{
|
|
iResult = 0;
|
|
}
|
|
|
|
return iResult;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Write a value to a PHY register through the MDIO interface.
|
|
* @param DevAddr: PHY port address
|
|
* @param RegAddr: PHY register address
|
|
* @param RegVal: Value to be written
|
|
* @retval 0 if OK -1 if Error
|
|
*/
|
|
static int32_t ETH_PHY_IO_WriteReg( uint32_t ulDevAddr,
|
|
uint32_t ulRegAddr,
|
|
uint32_t pulRegVal )
|
|
{
|
|
int32_t iResult = -1;
|
|
|
|
if( HAL_ETH_WritePHYRegister( &( xEthHandle ), ulDevAddr, ulRegAddr, pulRegVal ) == HAL_OK )
|
|
{
|
|
iResult = 0;
|
|
}
|
|
|
|
return iResult;
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/*******************************************************************************
|
|
* END PHY IO Functions
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* Ethernet Handling Functions
|
|
*******************************************************************************/
|
|
|
|
void ETH_IRQHandler( void )
|
|
{
|
|
HAL_ETH_IRQHandler( &( xEthHandle ) );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvSetFlagsAndNotify( uint32_t ulFlags )
|
|
{
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
/* Ethernet RX-Complete callback function, elsewhere declared as weak.
|
|
* No critical section needed, this function is called from an ISR. */
|
|
ulISREvents |= ulFlags;
|
|
|
|
/* Wakeup the prvEMACHandlerTask. */
|
|
if( xEMACTaskHandle != NULL )
|
|
{
|
|
vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xHigherPriorityTaskWoken ) );
|
|
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef * heth )
|
|
{
|
|
( void ) heth;
|
|
prvSetFlagsAndNotify( EMAC_IF_TX_EVENT );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef * heth )
|
|
{
|
|
( void ) heth;
|
|
prvSetFlagsAndNotify( EMAC_IF_RX_EVENT );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void HAL_ETH_DMAErrorCallback( ETH_HandleTypeDef * heth )
|
|
{
|
|
( void ) heth;
|
|
prvSetFlagsAndNotify( EMAC_IF_ERR_EVENT );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/*******************************************************************************
|
|
* END Ethernet Handling Functions
|
|
*******************************************************************************/
|
|
|
|
uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * ETH_RX_BUF_SIZE ]
|
|
#if ( ipconfigZERO_COPY_RX_DRIVER != 0 || ipconfigZERO_COPY_TX_DRIVER != 0 )
|
|
__attribute__( ( section( ".ethernet_data" ) ) )
|
|
#endif /* ( ipconfigZERO_COPY_RX_DRIVER != 0 || ipconfigZERO_COPY_TX_DRIVER != 0 ) */
|
|
__attribute__( ( aligned( 32 ) ) );
|
|
|
|
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
|
|
{
|
|
uint8_t * ucRAMBuffer = ucNetworkPackets;
|
|
uint32_t ul;
|
|
|
|
for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
|
|
{
|
|
pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
|
|
*( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
|
|
ucRAMBuffer += ETH_RX_BUF_SIZE;
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void vClearOptionBit( volatile uint32_t * pulValue,
|
|
uint32_t ulValue )
|
|
{
|
|
portENTER_CRITICAL();
|
|
*( pulValue ) &= ~( ulValue );
|
|
portEXIT_CRITICAL();
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
#if ( ipconfigHAS_PRINTF != 0 )
|
|
static size_t uxGetOwnCount( ETH_HandleTypeDef * heth )
|
|
{
|
|
BaseType_t xIndex;
|
|
BaseType_t xCount = 0;
|
|
ETH_RxDescListTypeDef * dmarxdesclist = &heth->RxDescList;
|
|
|
|
/* Count the number of RX descriptors that are owned by DMA. */
|
|
for( xIndex = 0; xIndex < ETH_RX_DESC_CNT; xIndex++ )
|
|
{
|
|
__IO const ETH_DMADescTypeDef * dmarxdesc =
|
|
( __IO const ETH_DMADescTypeDef * )dmarxdesclist->RxDesc[ xIndex ];
|
|
|
|
if( ( dmarxdesc->DESC3 & ETH_DMARXNDESCWBF_OWN ) != 0U )
|
|
{
|
|
xCount++;
|
|
}
|
|
}
|
|
|
|
return xCount;
|
|
}
|
|
#endif /* if ( ipconfigHAS_PRINTF != 0 ) */
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvEMACHandlerTask( void * pvParameters )
|
|
{
|
|
/* When sending a packet, all descriptors in the transmission channel may
|
|
* be occupied. In stat case, the program will wait (block) for the counting
|
|
* semaphore. */
|
|
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
|
|
|
|
#if ( ipconfigHAS_PRINTF != 0 )
|
|
size_t uxTXDescriptorsUsed = 0U;
|
|
size_t uxRXDescriptorsUsed = ETH_RX_DESC_CNT;
|
|
#endif
|
|
|
|
( void ) pvParameters;
|
|
|
|
for( ; ; )
|
|
{
|
|
BaseType_t xResult = 0;
|
|
|
|
#if ( ipconfigHAS_PRINTF != 0 )
|
|
{
|
|
size_t uxUsed;
|
|
size_t uxOwnCount;
|
|
|
|
/* Call a function that monitors resources: the amount of free network
|
|
* buffers and the amount of free space on the heap. See FreeRTOS_IP.c
|
|
* for more detailed comments. */
|
|
vPrintResourceStats();
|
|
|
|
/* Some more statistics: number of free descriptors. */
|
|
uxUsed = ETH_TX_DESC_CNT - uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
|
|
|
if( uxTXDescriptorsUsed < uxUsed )
|
|
{
|
|
uxTXDescriptorsUsed = uxUsed;
|
|
FreeRTOS_printf( ( "TX descriptors %u/%u\n",
|
|
uxTXDescriptorsUsed,
|
|
ETH_TX_DESC_CNT ) );
|
|
}
|
|
|
|
uxOwnCount = uxGetOwnCount( &( xEthHandle ) );
|
|
|
|
if( uxRXDescriptorsUsed > uxOwnCount )
|
|
{
|
|
uxRXDescriptorsUsed = uxOwnCount;
|
|
FreeRTOS_printf( ( "RX descriptors %u/%u\n",
|
|
uxRXDescriptorsUsed,
|
|
ETH_RX_DESC_CNT ) );
|
|
}
|
|
}
|
|
#endif /* ( ipconfigHAS_PRINTF != 0 ) */
|
|
|
|
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
|
|
|
|
/* Wait for the Ethernet MAC interrupt to indicate that another packet
|
|
* has been received. */
|
|
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0U )
|
|
{
|
|
vClearOptionBit( &( ulISREvents ), EMAC_IF_RX_EVENT );
|
|
xResult = prvNetworkInterfaceInput();
|
|
}
|
|
|
|
/* When a packet has been transmitted, the descriptor must be
|
|
* prepared for a next transmission.
|
|
* When using zero-copy, the network buffer must be released
|
|
* ( i.e. returned to the pool of network buffers ). */
|
|
|
|
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0U )
|
|
{
|
|
vClearOptionBit( &( ulISREvents ), EMAC_IF_TX_EVENT );
|
|
|
|
if( xSemaphoreTake( xTransmissionMutex, 10000U ) != pdFAIL )
|
|
{
|
|
ETH_Clear_Tx_Descriptors( &( xEthHandle ) );
|
|
xSemaphoreGive( xTransmissionMutex );
|
|
}
|
|
}
|
|
|
|
/* Some error has occurred, possibly an overflow or an underflow. */
|
|
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0U )
|
|
{
|
|
vClearOptionBit( &( ulISREvents ), EMAC_IF_ERR_EVENT );
|
|
|
|
xEthHandle.gState = HAL_ETH_STATE_READY;
|
|
/* Enable all interrupts */
|
|
HAL_ETH_Start_IT( &( xEthHandle ) );
|
|
xResult += prvNetworkInterfaceInput();
|
|
}
|
|
|
|
if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
|
|
{
|
|
/*
|
|
* The function xPhyCheckLinkStatus() returns pdTRUE if the
|
|
* Link Status has changes since it was called the last time.
|
|
*/
|
|
if( xSTM32H_GetPhyLinkStatus( pxMyInterface ) == pdFALSE )
|
|
{
|
|
/* Stop the DMA transfer. */
|
|
HAL_ETH_Stop_IT( &( xEthHandle ) );
|
|
/* Clear the Transmit buffers. */
|
|
memset( &( DMATxDscrTab ), '\0', sizeof( DMATxDscrTab ) );
|
|
/* Since the link is down, clear the descriptors. */
|
|
ETH_Clear_Tx_Descriptors( &( xEthHandle ) );
|
|
}
|
|
else
|
|
{
|
|
/* Something has changed to a Link Status, need re-check. */
|
|
prvEthernetUpdateConfig( pdFALSE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|