STM32H7 TCP DMATxDscrTab double declaration in main.c and NetworkInterface.c, if I remove it from one of the files it becomes undeclared

Hello,

Summary:

  • Environnement
  • What I want to do
  • What I have done
  • What my problem is
  • Questions
  • Code sample

##### ENVIRONMENT #####
Card : STM32H723ZG
PC : Computer with Windows 10
IDE : stm32cubeIDE
Compiler : GCC 9.2.0
FreeRTOS : 202212.01

##### What I want to do #####
I want to communicate from my STM32 to the computer using an ethernet cable and TCP/IP protocole.
From now I would like to be able to ping the card.
Ultimately I would like to send protobuf messages encoded and decoded on the card using nanopb and encoded and decoded on a raspberry pi 3b+ using protobuf’s functions.

##### What I have done #####
I was able to port freeRTOS into a cubeMX project and creating 2 tasks by msotly following this tutoriel : youtube /watch?v=vB5A4zmF6So&list=PLxGj5QMILu9GIB2PIgY_8RoRpRPOLvQ3J&index=2

Since there is a lot of steps I made a cheatSheet as a txt file:

CubeMx :
  1. Set a timer in Sys.
  2. Set the rest of what I need but make sure not to set freeRTOS in middlware (because we will port from official freeRTOS).
freeRTOS :
  1. Add the freeRTOS files to the project:
  • config (and set it)
  • sources
  • includes
  • compiler port (GCC)
  • memory manager (heap4)
  1. Add the folders freeRTOS the the project’s path.

  2. Include the folder freeRTOS to the project.

  3. In the main.c :
    Add the librairies:

  • “FreeRTOS.h”
  • “task.h”
    For each task
  • create the task handle : TaskHandle_t xLedTaskHandle;
  • initialise the function : void vLedTask(void *pvParameters);
  • create the task in the main function : xTaskCreate(vLedTask, “Led task”, 128, NULL, 1, &xLedTaskHandle);
  • define the function : void vLedTask(void *pvParameters){for (;;){HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    HAL_Delay(200);}}
    Start the RTOS in the main function : vTaskStartScheduler();
  1. Delete the double declaration of sys_tick, svc_handler and pendSV_handler in main.c.

##### What my problem is #####
I am now trying to port the TCP part of freeRTOS-plus.
After doing the same steps as the classic freeRTOS projet, I did extra steps, here is the cheatSheet for the TCP/IP part:

TCP/IP :
  1. Include to the file the folder freeRTOS plus TCP IP:
  • configIP
  • source
  • include
  • networkInterface stm32xxx
  • compiler
  • bufferManagement (bufferAllocation2.c)
  1. Complete the compiler files pack_struct_end.h and pack_struct_start.h.
    Just put attribute( (packed) ); in the end but nothing in the start.

  2. Complete the file freertosconfigip.h
    set :
    #define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN /* because I use DHCP */
    #define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 64
    #define ipconfigZERO_COPY_RX_DRIVER 1
    #define ipconfigZERO_COPY_TX_DRIVER 1
    #define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1
    #define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1

  3. Replace stm32h7xx_hal_eth.c and stm32h7xx_hal_eth.h with stm32hxx_hal_eth.c, tm32h7xx_hal_eth.h and stm32hxx_hal_eth.h

  4. Add the folders FreeRtosTcpIp tot he path.

  5. Include the folder freeRtosPlus.

  6. Modification of hal_config.h
    Add :
    #define ETH_TX_DESC_CNT 14U /* number of Ethernet Tx DMA descriptors /
    #define ETH_RX_DESC_CNT 8U /
    number of Ethernet Rx DMA descriptors /
    //mandatory
    #define HAL_ETH_MODULE_ENABLED
    #define USE_HAL_ETH_REGISTER_CALLBACKS 0U /
    ETH register callback disabled */
    //mac add
    #define ETH_MAC_ADDR0 ((uint8_t)0x02)
    #define ETH_MAC_ADDR1 ((uint8_t)0x00)
    //buffer size
    #define ETH_RX_BUF_SIZE 1524U
    #define ETH_TX_BUF_SIZE 1524U

Remove double declaration.

  1. STM32 are little endian (because ARM)
    ipconfigBYTE_ORDER must be set to pdFREERTOS_LITTLE_ENDIAN in FreeRTOSIPConfig.h
    #define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN

  2. Add in flash
    Add at the beginning in memory section :
    AXI_RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 128K /* .ethernet_data declared here. H723zg axi start at 2400 0000 ends at 2401 ffff */c

Add defore discard :
.ethernet_data :
{
PROVIDE_HIDDEN (__ethernet_data_start = .);
KEEP ((SORT(.ethernet_data.)))
KEEP ((.ethernet_data))
PROVIDE_HIDDEN (__ethernet_data_end = .);
} >AXI_RAM

  1. Add the following includes:
    /* Standard includes. /
    #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”

  2. Delete the double declaration of DMATxDscrTab and Rx
    One declaration in main.c and one declaration in NetworkInterface.c.

Note that I slightly change the directory architecture to make it simpler to include (I have to add to the path each folder individualy).

Previous folder architecture (only regarding the portable part of freeRTOS-plus-TCP):
→ portable
→ BufferManagement
BufferAllocation_2.c
→ Compiler
→ GGC
pack_struct_end.h
pack_struct_start.h
→ NetworkInterface
→ STM32Hxx
NetworkInterface.c
stm32h7xx_hal_eth.h (that I removed and placed instead of the original stm32 file)
stm32hxx_hal_eth.c (that I removed and placed instead of the original stm32 file)
stm32hxx_hal_eth.h (that I removed and placed instead of the original stm32 file)
→ include (the common folder contains the same file so I only kept one)
phyHandling.h

Updated folder architecture (only regarding the portable part of freeRTOS-plus-TCP):
→ portable
BufferAllocation_2.c
NetworkInterface.c
pack_struct_end.h
pack_struct_start.h
phyHandling.h

When I build the project before step 11 I get an error saying that both descriptors DMATxDscrTab and DMARxDscrTab have multiple declarations in the files main.c and in the file NetworkInterface.c.

Exact error : "Description Resource Path Location Type
./freeRTOS/FreeRTOS-Plus-TCP/source/portable/NetworkInterface.o:D:/Documents/stm32h7 projets/6_0_H723ZG_freeRtosTcp_testBasic/Debug/…/freeRTOS/FreeRTOS-Plus-TCP/source/portable/NetworkInterface.c:128: multiple definition of `DMARxDscrTab’; ./Core/Src/main.o:D:/Documents/stm32h7 projets/6_0_H723ZG_freeRtosTcp_testBasic/Debug/…/Core/Src/main.c:17: first defined here 6_0_H723ZG_freeRtosTcp_testBasic C/C++ Problem
"
The lines in question in main.c:

ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection")));
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection")));

The lines in question in NetworkInterface.c :

ETH_DMADescTypeDef DMATxDscrTab[ ETH_TX_DESC_CNT ]    __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );
ETH_DMADescTypeDef DMARxDscrTab[ ETH_RX_DESC_CNT ]    __attribute__( ( section( ".ethernet_data" ), aligned( 32 ) ) );

I figured that just like the HAL_ETH files or the sys_check definitions, I had to remove the one generated by cubeMX, so I deleted the declaration in the main.c.
I then get an error “main.c:116:22: error: ‘DMATxDscrTab’ undeclared (first use in this function)” (some for Rx descriptor).

I tryed to keep the declaration in the main.c and remove the one in NetworkInterface.c and this time I get the same error but saying that it is undeclared and used in the NetworkInterface.c file.
Error : “freeRTOS/FreeRTOS-Plus-TCP/source/portable/NetworkInterface.c:944:28: error: ‘DMATxDscrTab’ undeclared (first use in this function)”

##### Questions #####

  1. I understand why it is declared twice but then why does it becomes undeclared when I remove a single declaration? It should stay declared in the other file and since I link both through header files there should be no problem.
  2. How can I fix the “multiple declaration” / “undeclared” issue? (c.f. question 1, I just want to make separate questions)
  3. In this readme : github /FreeRTOS/FreeRTOS-Plus-TCP/tree/a3f418a20dd05c5aecb362f52ee7344a606ac766/source/portable/NetworkInterface/STM32Hxx you mention the important DMCA registers, what should I do with them? Should I copy paste them in the FreeRTOSIPConfig.h ? (I tryed that (which seemed weird) and I got errors.)

Thank you in advance for your answers.

Regards

Gaetan

You need to remove all the references to DMATxDscrTab from main.c as well. Can you paste the code in main.c where it is used?

1 Like

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 );
            }
        }
    }
}
/*-----------------------------------------------------------*/

ETH initialization is done in NetworkInterface.c. You should remove MX_ETH_Init and its invocation from main.c:

/* 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")));
*/

/* cube mx generated handler */
UART_HandleTypeDef huart3;

/* task handlers */


/* cube mx generated function definitions */
void SystemClock_Config(void);
static void MX_GPIO_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_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_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 */
1 Like