Hi and thank you for your answer.
I removed the lines (117 and 118) using the descriptors and now it compiles, thanks!
Here is all the code in the main:
/* Standard includes. */
#include "main.h"
#include "string.h"
#include <stdint.h>
#include <stdio.h>
#include <limits.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "NetworkInterface.h"
/*
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection")));
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection")));
*/
ETH_TxPacketConfig TxConfig;
/* cube mx generated handler */
ETH_HandleTypeDef heth;
UART_HandleTypeDef huart3;
/* task handlers */
/* cube mx generated function definitions */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ETH_Init(void);
static void MX_USART3_UART_Init(void);
static void MX_USB_OTG_HS_USB_Init(void);
/* task function definitions */
int main(void)
{
/* cube mx generated */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ETH_Init();
MX_USART3_UART_Init();
MX_USB_OTG_HS_USB_Init();
/* task creation */
/* starting rtos */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 275;
RCC_OscInitStruct.PLL.PLLP = 1;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
}
static void MX_ETH_Init(void)
{
static uint8_t MACAddr[6];
heth.Instance = ETH;
MACAddr[0] = 0x00;
MACAddr[1] = 0x80;
MACAddr[2] = 0xE1;
MACAddr[3] = 0x00;
MACAddr[4] = 0x00;
MACAddr[5] = 0x00;
heth.Init.MACAddr = &MACAddr[0];
heth.Init.MediaInterface = HAL_ETH_RMII_MODE;
/*
heth.Init.TxDesc = DMATxDscrTab;
heth.Init.RxDesc = DMARxDscrTab;
*/
heth.Init.RxBuffLen = 1524;
if (HAL_ETH_Init(&heth) != HAL_OK)
{
Error_Handler();
}
memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
}
static void MX_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart3.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart3, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart3, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart3) != HAL_OK)
{
Error_Handler();
}
}
static void MX_USB_OTG_HS_USB_Init(void)
{
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOB, LED_GREEN_Pin|LED_RED_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(USB_FS_PWR_EN_GPIO_Port, USB_FS_PWR_EN_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LED_GREEN_Pin|LED_RED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USB_FS_PWR_EN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(USB_FS_PWR_EN_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USB_FS_OVCR_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(USB_FS_OVCR_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USB_FS_VBUS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(USB_FS_VBUS_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USB_FS_ID_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_HS;
HAL_GPIO_Init(USB_FS_ID_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LED_YELLOW_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_YELLOW_GPIO_Port, &GPIO_InitStruct);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1) {
HAL_IncTick();
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
And all the code in NetworkInterface.c :
/*
* Some constants, hardware definitions and comments taken from ST's HAL driver
* library, COPYRIGHT(c) 2015 STMicroelectronics.
*/
/*
* FreeRTOS+TCP V3.1.0
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* 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 "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;
/*
* 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 */
#ifndef DMARXDSCRTAB
#define DMARXDSCRTAB
ETH_DMADescTypeDef DMARxDscrTab[ ETH_RX_DESC_CNT ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
#endif
/* 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 */
#ifndef DMATXDSCRTAB
#define DMATXDSCRTAB
ETH_DMADescTypeDef DMATxDscrTab[ ETH_TX_DESC_CNT ] __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
#endif
/* 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 );
static size_t uxGetOwnCount( ETH_HandleTypeDef * heth );
/*-----------------------------------------------------------*/
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
};
/*-----------------------------------------------------------*/
/*******************************************************************************
* 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;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
BaseType_t xResult = pdFAIL;
HAL_StatusTypeDef xHalEthInitStatus;
size_t uxIndex = 0;
if( xMacInitStatus == eMACInit )
{
/*
* 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 * ) FreeRTOS_GetMACAddress();
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 ) );
if( xHalEthInitStatus == HAL_OK )
{
/* 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 );
}
/* Configure the MDIO Clock */
HAL_ETH_SetMDIOClockRange( &( xEthHandle ) );
/* 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;
}
}
else
{
xMacInitStatus = eMACFailed;
}
} /* ( xMacInitStatus == eMACInit ) */
if( xMacInitStatus == eMACPass )
{
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. */
}
}
return xResult;
}
/*-----------------------------------------------------------*/
BaseType_t xGetPhyLinkStatus( void )
{
BaseType_t xReturn;
if( xPhyObject.ulLinkStatusMask != 0U )
{
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
BaseType_t xReleaseAfterSend )
{
BaseType_t xResult = pdFAIL;
TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 100U );
uint8_t * pucTXBuffer;
if( xGetPhyLinkStatus() == pdPASS )
{
#if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
/* Zero-copy method, pass the buffer. */
pucTXBuffer = pxDescriptor->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( pxDescriptor->xDataLength <= sizeof( Tx_Buff[ 0 ] ) );
#endif
ETH_BufferTypeDef xTransmitBuffer =
{
.buffer = pucTXBuffer,
.len = pxDescriptor->xDataLength,
.next = NULL /* FreeRTOS+TCP does not use linked buffers. */
};
/* This is the total length, which is equal to the buffer. */
xTxConfig.Length = pxDescriptor->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, pxDescriptor->pucEthernetBuffer, pxDescriptor->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( pxDescriptor );
}
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
};
/* 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();
}
/*-----------------------------------------------------------*/
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;
}
/*-----------------------------------------------------------*/
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 );
size_t uxTXDescriptorsUsed = 0U;
size_t uxRXDescriptorsUsed = ETH_RX_DESC_CNT;
( 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 ) != pdFALSE )
{
/*
* The function xPhyCheckLinkStatus() returns pdTRUE if the
* Link Status has changes since it was called the last time.
*/
if( xGetPhyLinkStatus() == 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 );
}
}
}
}
/*-----------------------------------------------------------*/