vApplicationIPNetworkEventHook not called before socket creaton but blocking socket creation

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 ping my STM32 and later set it as a client (in this question I tried maing a server, not a client).

You can get more informations about my project here : STM32H7 TCP DMATxDscrTab double declaration in main.c and NetworkInterface.c, if I remove it from one of the files it becomes undeclared

##### What I have done #####
I was able to make a simple FreeRTOS project with 2 tasks. I then moved to to initializing FreeRTOS plus TCP.

##### What my problem is #####
I started trying to make a TCP server.

I am following the tutorial here : TCP Networking Tutorial - Creating, Configuring and Binding TCP Client and Server Sockets
I also need to choose between reading or sending data, so I decided to receive data following this tutorial : TCP Networking Tutorial - Receiving Data Using a TCP Socket

When I run, I get stuck in the
configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );
on line 140.

This is because
FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);
returns FREERTOS_INVALID_SOCKET.

In the file FreeRTOS_Sockets.c, in the function FreeRTOS_socket, this “if” statement is entered :

    if( prvDetermineSocketSize( xDomain, xType, xProtocolCpy, &uxSocketSize ) == pdFAIL )
    {
        /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
        /* coverity[misra_c_2012_rule_11_4_violation] */
        xReturn = FREERTOS_INVALID_SOCKET;
    }

So prvDetermineSocketSize returns pdFail.
in the function prvDetermineSocketSize, this “if” statement is entered :

    /* Asserts must not appear before it has been determined that the network
     * task is ready - otherwise the asserts will fail. */
    if( xIPIsNetworkTaskReady() == pdFALSE )
    {
        xReturn = pdFAIL;
    }

And finaly, in the file FreeRTOS_IP.c, xIPIsNetworkTaskReady is defined as:

BaseType_t xIPIsNetworkTaskReady( void )
{
    return xIPTaskInitialised;
}

So xIPTaskInitialised is set to pdFALSE.

In file FreeRTOS_IP.c, we can see the declaration of xIPTaskInitialised set to pdFALSE on line 227.
The only way for xIPTaskInitialised to be set to psTRUE is in the same file on line 295 inside the function prvIPTask.
I did a global researche and prvIPTask is not mentionned (called) in any file other than FreeRTOS_IP.c.
It mention in the brief

The IP task handles all requests from the user application and the network interface. It receives messages through a FreeRTOS queue called ‘xNetworkEventQueue’.

So I don’t know when and how this function is called as it is not one of the “hook/callback API” mentionned in the website.

##### Question #####

  1. What do I have to change in my program to make it work :upside_down_face:
  2. When and where is prvIPTask called?
  3. Should I manually set xTasksAlreadyCreated to pdTRUE ?

##### Code sample #####
The main:

/* Standard includes. */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <ctype.h>

//#include <winsock.h>

/*
#ifdef __linux__  // include the socket library
    #include <sys/socket.h>
#elif _WIN32
    #include <Winsock2.h>
#else
	#include "socket.h"
#endif
*/

/* cubeMX/HAL includes */
#include "main.h"
#include "string.h"

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"

/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "phyHandling.h"
#if( ipconfigMULTI_INTERFACE != 0 )
	#include "FreeRTOS_Routing.h"
	#include "FreeRTOS_ND.h"
#endif

ETH_TxPacketConfig TxConfig;

#define usUsedStackSize 128
#define BUFFER_SIZE 512

/* cube mx generated handler */
ETH_HandleTypeDef heth;
UART_HandleTypeDef huart3;

/* task handlers */


/* The MAC address array is not declared const as the MAC address will
normally be read from an EEPROM and not hard coded (in real deployed applications).*/
static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x80, 0xE1, 0x00, 0x00, 0x00 };

/* Define the network addressing.  These parameters will be used if either
ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration failed. */
static const uint8_t ucIPAddress[ 4 ];
static const uint8_t ucNetMask[ 4 ];
static const uint8_t ucGatewayAddress[ 4 ];

/* The following is the address of the DNS server. */
static const uint8_t ucDNSServerAddress[ 4 ] = { 192, 168, 73, 220 };

/* Random Number Generator variable. */
static RNG_HandleTypeDef hrng;

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

/* TCP function definition */
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent );
BaseType_t xApplicationGetRandomNumber( uint32_t *pulValue );
void vCreateTCPServerSocket(void);
void prvProcessData(char *cRxedData, BaseType_t lBytesReceived);

/* task function definitions (the ones that doens't do tcp thing */
static void prvEchoClientRxTask(void *pvParameters);

int main(void)
{
	/* cube mx generated */
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
	MX_USART3_UART_Init();
	MX_USB_OTG_HS_USB_Init();

	uint8_t buffer[20];
	sprintf((char*)buffer, "Entered main\r\n\n");
	HAL_UART_Transmit(&huart3, buffer, strlen((char*)buffer), HAL_MAX_DELAY);

	/* TCP init */
	FreeRTOS_IPInit(ucIPAddress,
	                ucNetMask,
	                ucGatewayAddress,
	                ucDNSServerAddress,
	                ucMACAddress );

	vCreateTCPServerSocket();	//allocate and initialise a socket

	/* task creation */


	/* starting rtos scheduler */
	vTaskStartScheduler();

	for(;;);
}

void vCreateTCPServerSocket(void)
{
	struct freertos_sockaddr xClient, xBindAddress;
	Socket_t xListeningSocket, xConnectedSocket;
	socklen_t xSize = sizeof( xClient );
	static const TickType_t xReceiveTimeOut = portMAX_DELAY;
	const BaseType_t xBacklog = 20;

    /* Attempt to open the socket. */
    xListeningSocket = FreeRTOS_socket(FREERTOS_AF_INET,
    		                           FREERTOS_SOCK_STREAM,  /* SOCK_STREAM for TCP. */
									   FREERTOS_IPPROTO_TCP);

    /* Check the socket was created. */
    configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );	//block here because xListeningSocket return FREERTOS_INVALID_SOCKET

    /* If FREERTOS_SO_RCVBUF or FREERTOS_SO_SNDBUF are to be used with
    FreeRTOS_setsockopt() to change the buffer sizes from their default then do
    it here!.  (see the FreeRTOS_setsockopt() documentation. */

    /* If ipconfigUSE_TCP_WIN is set to 1 and FREERTOS_SO_WIN_PROPERTIES is to
    be used with FreeRTOS_setsockopt() to change the sliding window size from
    its default then do it here! (see the FreeRTOS_setsockopt()
    documentation. */

    /* Set a time out so accept() will just wait for a connection. */
    FreeRTOS_setsockopt( xListeningSocket,
                         0,
                         FREERTOS_SO_RCVTIMEO,
                         &xReceiveTimeOut,
                         sizeof( xReceiveTimeOut ) );

    /* Set the listening port to 10000. */
    xBindAddress.sin_port = ( uint16_t ) 10000;
    xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );

    /* Bind the socket to the port that the client RTOS task will send to. */
    FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

    /* Set the socket into a listening state so it can accept connections.
    The maximum number of simultaneous connections is limited to 20. */
    FreeRTOS_listen( xListeningSocket, xBacklog );

    for( ;; )
    {
        /* Wait for incoming connections. */
        xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
        configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );

        /* Spawn a RTOS task to handle the connection. */
        xTaskCreate( prvEchoClientRxTask,
                     "EchoServer",
                     usUsedStackSize,
                     ( void * ) xConnectedSocket,
                     tskIDLE_PRIORITY,
                     NULL );
    }
}

static void prvEchoClientRxTask( void *pvParameters )
{
	Socket_t xSocket;
	static char cRxedData[ BUFFER_SIZE ];
	BaseType_t lBytesReceived;

    /* It is assumed the socket has already been created and connected before
    being passed into this RTOS task using the RTOS task's parameter. */
    xSocket = ( Socket_t ) pvParameters;

    for( ;; )
    {
        /* Receive another block of data into the cRxedData buffer. */
        lBytesReceived = FreeRTOS_recv( xSocket, &cRxedData, BUFFER_SIZE, 0 );

        if( lBytesReceived > 0 )
        {
            /* Data was received, process it here. */
            prvProcessData(cRxedData, lBytesReceived);
        }
        else if( lBytesReceived == 0 )
        {
            /* No data was received, but FreeRTOS_recv() did not return an error.
            Timeout? */
        }
        else
        {
            /* Error (maybe the connected socket already shut down the socket?).
            Attempt graceful shutdown. */
            FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
            break;
        }
    }

    /* The RTOS task will get here if an error is received on a read.  Ensure the
    socket has shut down (indicated by FreeRTOS_recv() returning a -pdFREERTOS_ERRNO_EINVAL
    error before closing the socket). */

    while( FreeRTOS_recv( xSocket, &cRxedData, BUFFER_SIZE, 0 ) >= 0 )
    {
        /* Wait for shutdown to complete.  If a receive block time is used then
        this delay will not be necessary as FreeRTOS_recv() will place the RTOS task
        into the Blocked state anyway. */
        vTaskDelay(pdMS_TO_TICKS(250));

        /* Note - real applications should implement a timeout here, not just
        loop forever. */
    }

    /* Shutdown is complete and the socket can be safely closed. */
    FreeRTOS_closesocket( xSocket );

    /* Must not drop off the end of the RTOS task - delete the RTOS task. */
    vTaskDelete( NULL );
}

void prvProcessData(char *cRxedData, BaseType_t lBytesReceived)
{

}

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
	static BaseType_t xTasksAlreadyCreated = pdFALSE;
	//static BaseType_t xIPTaskInitialised = pdFALSE;

	uint8_t buffer[20];
	sprintf((char*)buffer, "Entered eNetwork\r\n");
	HAL_UART_Transmit(&huart3, buffer, strlen((char*)buffer), HAL_MAX_DELAY);

    /* Both eNetworkUp and eNetworkDown events can be processed here. */
    if( eNetworkEvent == eNetworkUp )
    {
        /* Create the tasks that use the TCP/IP stack if they have not already
        been created. */
        if( xTasksAlreadyCreated == pdFALSE )
        {
            /*
             * For convenience, tasks that use FreeRTOS-Plus-TCP can be created here
             * to ensure they are not created before the network is usable.
             */

            xTasksAlreadyCreated = pdTRUE;
            //xIPTaskInitialised = pdTRUE;
        }
    }
}

BaseType_t xApplicationGetRandomNumber( uint32_t *pulValue )
{
HAL_StatusTypeDef xResult;
BaseType_t xReturn;
uint32_t ulValue;

	xResult = HAL_RNG_GenerateRandomNumber( &hrng, &ulValue );
	if( xResult == HAL_OK )
	{
		xReturn = pdPASS;
		*pulValue = ulValue;
	}
	else
	{
		xReturn = pdFAIL;
	}
	return xReturn;
}

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 */

The FreeRTOSIPConfig.h :

#ifndef FREERTOS_IP_CONFIG_H
#define FREERTOS_IP_CONFIG_H

#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN

#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
#define ipconfigUSE_NETWORK_EVENT_HOOK 				1

#endif /* FREERTOS_IP_CONFIG_H */

Thanks in advance for your help!
If you have any questions to make the post clearer, don’t hesitate.

Hi @GaetanGodart,

To initialize the IP stack, you must follow the step in Initialising the TCP/IP Stack. After starting scheduler, prvIPTask would be executed as an individual task. Then you should be able to create sockets successfully.

Thanks.

You are calling vCreateTCPServerSocket function from main before starting the scheduler and this function never returns. This means that the scheduler is not getting started in your case.

You should create the server task from the vApplicationIPNetworkEventHook:

/* Standard includes. */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <ctype.h>

//#include <winsock.h>

/*
#ifdef __linux__  // include the socket library
    #include <sys/socket.h>
#elif _WIN32
    #include <Winsock2.h>
#else
	#include "socket.h"
#endif
*/

/* cubeMX/HAL includes */
#include "main.h"
#include "string.h"

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"

/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "phyHandling.h"
#if( ipconfigMULTI_INTERFACE != 0 )
	#include "FreeRTOS_Routing.h"
	#include "FreeRTOS_ND.h"
#endif

ETH_TxPacketConfig TxConfig;

#define usUsedStackSize 512
#define BUFFER_SIZE 512

/* cube mx generated handler */
ETH_HandleTypeDef heth;
UART_HandleTypeDef huart3;

/* task handlers */


/* The MAC address array is not declared const as the MAC address will
normally be read from an EEPROM and not hard coded (in real deployed applications).*/
static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x80, 0xE1, 0x00, 0x00, 0x00 };

/* Define the network addressing.  These parameters will be used if either
ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration failed. */
static const uint8_t ucIPAddress[ 4 ];
static const uint8_t ucNetMask[ 4 ];
static const uint8_t ucGatewayAddress[ 4 ];

/* The following is the address of the DNS server. */
static const uint8_t ucDNSServerAddress[ 4 ] = { 192, 168, 73, 220 };

/* Random Number Generator variable. */
static RNG_HandleTypeDef hrng;

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

/* TCP function definition */
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent );
BaseType_t xApplicationGetRandomNumber( uint32_t *pulValue );
void prvProcessData(char *cRxedData, BaseType_t lBytesReceived);

/* task function definitions (the ones that doens't do tcp thing */
static void prvEchoClientRxTask(void *pvParameters);
static void prvTCPServerTask(void *pvParameters);

int main(void)
{
	/* cube mx generated */
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
	MX_USART3_UART_Init();
	MX_USB_OTG_HS_USB_Init();

	uint8_t buffer[20];
	sprintf((char*)buffer, "Entered main\r\n\n");
	HAL_UART_Transmit(&huart3, buffer, strlen((char*)buffer), HAL_MAX_DELAY);

	/* TCP init */
	FreeRTOS_IPInit(ucIPAddress,
	                ucNetMask,
	                ucGatewayAddress,
	                ucDNSServerAddress,
	                ucMACAddress );

	/* starting rtos scheduler */
	vTaskStartScheduler();

	for(;;);
}

static void prvTCPServerTask(void *pvParameters)
{
	struct freertos_sockaddr xClient, xBindAddress;
	Socket_t xListeningSocket, xConnectedSocket;
	socklen_t xSize = sizeof( xClient );
	static const TickType_t xReceiveTimeOut = portMAX_DELAY;
	const BaseType_t xBacklog = 20;

    ( void )pvParameters;

    /* Attempt to open the socket. */
    xListeningSocket = FreeRTOS_socket(FREERTOS_AF_INET,
    		                           FREERTOS_SOCK_STREAM,  /* SOCK_STREAM for TCP. */
									   FREERTOS_IPPROTO_TCP);

    /* Check the socket was created. */
    configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );	//block here because xListeningSocket return FREERTOS_INVALID_SOCKET

    /* If FREERTOS_SO_RCVBUF or FREERTOS_SO_SNDBUF are to be used with
    FreeRTOS_setsockopt() to change the buffer sizes from their default then do
    it here!.  (see the FreeRTOS_setsockopt() documentation. */

    /* If ipconfigUSE_TCP_WIN is set to 1 and FREERTOS_SO_WIN_PROPERTIES is to
    be used with FreeRTOS_setsockopt() to change the sliding window size from
    its default then do it here! (see the FreeRTOS_setsockopt()
    documentation. */

    /* Set a time out so accept() will just wait for a connection. */
    FreeRTOS_setsockopt( xListeningSocket,
                         0,
                         FREERTOS_SO_RCVTIMEO,
                         &xReceiveTimeOut,
                         sizeof( xReceiveTimeOut ) );

    /* Set the listening port to 10000. */
    xBindAddress.sin_port = ( uint16_t ) 10000;
    xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );

    /* Bind the socket to the port that the client RTOS task will send to. */
    FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

    /* Set the socket into a listening state so it can accept connections.
    The maximum number of simultaneous connections is limited to 20. */
    FreeRTOS_listen( xListeningSocket, xBacklog );

    for( ;; )
    {
        /* Wait for incoming connections. */
        xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
        configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET );

        /* Spawn a RTOS task to handle the connection. */
        xTaskCreate( prvEchoClientRxTask,
                     "EchoClient",
                     usUsedStackSize,
                     ( void * ) xConnectedSocket,
                     tskIDLE_PRIORITY,
                     NULL );
    }
}

static void prvEchoClientRxTask( void *pvParameters )
{
	Socket_t xSocket;
	static char cRxedData[ BUFFER_SIZE ];
	BaseType_t lBytesReceived;

    /* It is assumed the socket has already been created and connected before
    being passed into this RTOS task using the RTOS task's parameter. */
    xSocket = ( Socket_t ) pvParameters;

    for( ;; )
    {
        /* Receive another block of data into the cRxedData buffer. */
        lBytesReceived = FreeRTOS_recv( xSocket, &cRxedData, BUFFER_SIZE, 0 );

        if( lBytesReceived > 0 )
        {
            /* Data was received, process it here. */
            prvProcessData(cRxedData, lBytesReceived);
        }
        else if( lBytesReceived == 0 )
        {
            /* No data was received, but FreeRTOS_recv() did not return an error.
            Timeout? */
        }
        else
        {
            /* Error (maybe the connected socket already shut down the socket?).
            Attempt graceful shutdown. */
            FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
            break;
        }
    }

    /* The RTOS task will get here if an error is received on a read.  Ensure the
    socket has shut down (indicated by FreeRTOS_recv() returning a -pdFREERTOS_ERRNO_EINVAL
    error before closing the socket). */

    while( FreeRTOS_recv( xSocket, &cRxedData, BUFFER_SIZE, 0 ) >= 0 )
    {
        /* Wait for shutdown to complete.  If a receive block time is used then
        this delay will not be necessary as FreeRTOS_recv() will place the RTOS task
        into the Blocked state anyway. */
        vTaskDelay(pdMS_TO_TICKS(250));

        /* Note - real applications should implement a timeout here, not just
        loop forever. */
    }

    /* Shutdown is complete and the socket can be safely closed. */
    FreeRTOS_closesocket( xSocket );

    /* Must not drop off the end of the RTOS task - delete the RTOS task. */
    vTaskDelete( NULL );
}

void prvProcessData(char *cRxedData, BaseType_t lBytesReceived)
{

}

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
	static BaseType_t xTasksAlreadyCreated = pdFALSE;
	//static BaseType_t xIPTaskInitialised = pdFALSE;

	uint8_t buffer[20];
	sprintf((char*)buffer, "Entered eNetwork\r\n");
	HAL_UART_Transmit(&huart3, buffer, strlen((char*)buffer), HAL_MAX_DELAY);

    /* Both eNetworkUp and eNetworkDown events can be processed here. */
    if( eNetworkEvent == eNetworkUp )
    {
        /* Create the tasks that use the TCP/IP stack if they have not already
        been created. */
        if( xTasksAlreadyCreated == pdFALSE )
        {
            /*
             * For convenience, tasks that use FreeRTOS-Plus-TCP can be created here
             * to ensure they are not created before the network is usable.
             */
            xTaskCreate( prvTCPServerTask,
                        "EchoServer",
                        usUsedStackSize,
                        NULL,
                        tskIDLE_PRIORITY,
                        NULL );
            xTasksAlreadyCreated = pdTRUE;
            //xIPTaskInitialised = pdTRUE;
        }
    }
}

BaseType_t xApplicationGetRandomNumber( uint32_t *pulValue )
{
HAL_StatusTypeDef xResult;
BaseType_t xReturn;
uint32_t ulValue;

	xResult = HAL_RNG_GenerateRandomNumber( &hrng, &ulValue );
	if( xResult == HAL_OK )
	{
		xReturn = pdPASS;
		*pulValue = ulValue;
	}
	else
	{
		xReturn = pdFAIL;
	}
	return xReturn;
}

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

Thank you for your asnwer Aggarg.

It makes sense to put it there indeed, I was just confused because in the exemple they define it as “void vCreateTCPServerSocket(void)” which looks more like a function than a task.

I applied the changes: moving it to a xTaskCreate function in the event hook callback and redefining it with the right type. I did not copy paste your provided code because you changed the name of the function, I don’t know if you changed something else and I want to understand the code in my programm.
I also tried to copy paste your main later on but got the same result as what is below:

It builds without error or warning.

When I run (in debug mode), I end up in what look like an infinite loop.

StartScheduler is executed.
Inside StartScheduler, StartFirstTask is executed.
Inside StartFirstTask, prvProcessTimerOrBlockTask is executed in timers.c, line 596.
If I step into prvProcessTimerOrBlockTask and run it step by step I am able to complete the function and exit it.
I then end up on line 599 at the function prvProcessReceivedCommands.
Now whatever I try to do (run from there, step into, step over) I get stuck in an infinte loop without even entering the function (the debugger stays on line 599 in timers.c file.

If when I arrive to prvProcessTimerOrBlockTask and step over (which execute the function but do not put the user into it and stop at every line), I should end up on line 599 at the next function which is prvProcessReceivedCommands but instead I enter the infinite loop and stay on line 596 instead of going to line 599.

That is looks very unusual.

Edit :
I open Putty to be able to see what is sent to the USART3.
I get “Entered main” which is printed at the start of the main.
But I never get “Entered eNetwork” which should be printed when entering the network event hook callback.

Put a breakpoint here and see if the ETH interrupt is firing - FreeRTOS-Plus-TCP/NetworkInterface.c at main ¡ FreeRTOS/FreeRTOS-Plus-TCP ¡ GitHub

Do you any light blinking when you insert the Ethernet cable?

When I debugged I don’t think I ever entered networkinterface.c before hitting the “infinite loop” from timers.c.

I did put a breakpoint there but never reached it.

FYI, this is the state the debugger is in when in the “infinite loop” :
Thread #1 [main] 1 [core: 0] (Running : User Request)

Also, I plug the usb cable from STM to PC then the ETH cable from STM to router/relay and then I flash the STM.

When I unplug the ETH cable the replug it, no led on the board blink but there is 2 leds on the port itself, one green that stays on and one orange that is mostly on but turns off for like 10ms on average 2 times a second at random intervals.

I plugged another card (same exact model, just I bought 3) and got the same led behavior as well as debugging behavior.

Please share your complete project.

There it is:

zipped version : Download files - Filemail

Available one week (until 15th of june 2023).

How did you copy the FreeRTOS+TCP files? Did you copy all the files in this folder - FreeRTOS-Plus-TCP/source/portable/NetworkInterface/STM32Hxx at main ¡ FreeRTOS/FreeRTOS-Plus-TCP ¡ GitHub? If yes, where did you copy the HAL files?

Here you can see all the files underFreeRTOSPlusTcp=>Source=>Portable :

As I said in my previous post, I put all the portable files (bufferManagement, Compiler and NetworkInterface) into a single folder for easier access, which hsouldn’t change the behavior.

Regarding the STM32H7xx folder, I do not see CMakeList.txt file in my original download (I kept all the files in thos original download [dowloaded from : FreeRTOS - Free RTOS Source Code Downloads, the official FreeRTOS zip file release download]).
I kept the NetworkInterface.c in this folder but moved the hal_eth files directly to the project (Replace stm32h7xx_hal_eth.c and stm32h7xx_hal_eth.h with stm32hxx_hal_eth.c, tm32h7xx_hal_eth.h and stm32hxx_hal_eth.h) :
Hal eth files - Album on Imgur

I just added the cmake file into the “source” foldern rebuilt and redebugged but got the same issue.

Here is the updated project -
H723ZG_freeRtosTcp_testBasic.zip (1.7 MB)

There were multiple issues with the project -

  1. Linker script was wrong - it defined the same memory location with a different name (AXI_RAM) which would lead to data corruption. I placed ethernet_data in RAM_D1.
  2. Ethernet interrupt was not enabled.
  3. RNG was not initialized.

After this changes, the application code works.

2 Likes

Thank you very much.

It does seems to work so far, I will look more into it and try not to bother you anymore haha : D

To make sure I understood what you did :

  1. Removed the memory specification of AXI SRAM in the flash.id file. and changed “>AXI_SRAM” to “>RAM_D1”
  2. Added NVIC_EnableIRQ(ETH_IRQn);" and “NVIC_SetPriority(ETH_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);” in the main.c
  3. Added “MX_RNG_Init();” in main.c

You also added :
“#define ipconfigHAS_PRINTF 1
#define FreeRTOS_debug_printf( x ) printf x
#define FreeRTOS_printf( x ) printf x”
in the FreeRTOSIPConfig.h file

Finaly you change those define :
“#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 512 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 60 * 1024 ) )”
in the FreeRTOSConfig.h file.

You can use a diff tool to compare the two projects. From what I remember, other than the changes you described, I made the following changes -

  • Added the HAL_RNG_MspInit and HAL_RNG_MspDeInit in stm32h7xx_hal_msp.c.
  • Added the following to main.c to route print messages to UART -
int _write(int file, char *ptr, int len)
{
  HAL_UART_Transmit(&huart3, ( const uint8_t * ) ptr, len, HAL_MAX_DELAY);
  return len;
}
1 Like

Thank you for your help!