Nucleo-F439ZI FreeRTOS + TCP always returns a byte count of 0xfffffff4

SOFTWARE:
FreeRTOSv202406.01-LTS. Using CMake I have successfully built the project, including FreeRTOS kernel and TCP.

SETUP:
I have the Nucleo-F439ZI, set up a server, directly connected to a PC. The PC isrunning Linux (I’ve also tried using a switch, TPE-TG50G), using an Ethernet cable.

PARAMETERS:

  • Nucleo:
    IP ADDR -------> 192.168.55.11
    Subnet Mask → 255.255.255.0
    PORT -----------> 10000
    MAC ------------> 00:80:e1:00:00:00
    DNS/GATEWay-> Not used (LAN direct connection to PC)

  • PC:
    IP ADDR --------> 192.168.55.132
    Subnet MASK → 255.255.255.0

ISSUE:
I’m able to ping the Nucleo fine from the PC, verified through Wireshark (can’t upload pcap as I’m a new user), getting a successful [SYN}, [SYN, ACK] and [ACK]. When I go to send a message of 0xDE AD BE EF to the Nucleo Wireshark shows it keeps trying a [TCP Retransmission].

When I put a break point the code I see that FreeRTOS is getting notified of the message, and in a task that called FreeRTOS_recv(…) it calls this function and tries to decode the message. This will then call the prvRECVWait function, which always returns a value of 0xfffffff4. Any idea of what could be causing this.


CODE BELOW

  • eth_helper.cpp file (used to create the TCP link and start a task for the connection instance)
// ---- FreeRTOS includes -----
#include <FreeRTOS.h>
#include "task.h"

#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Routing.h"
#include "NetworkInterface.h"

#include "eth_helper.hpp"
#include "gpio.h"
#include "print_setup.hpp"

extern const uint8_t ucIPAddress[4];
extern const uint8_t ucNetMask[4];
// extern const uint8_t ucGatewayAddress[4];
// extern const uint8_t ucDNSServerAddress[4];
extern uint8_t uc_MACAddress[6];

#ifdef __cplusplus
extern "C"
{
#endif

    NetworkInterface_t *pxSTM32Fxx_FillInterfaceDescriptor(BaseType_t xEMACIndex,
                                                           NetworkInterface_t *pxInterface);

    void setup_ethernet_hw(ETH_HandleTypeDef &heth)
    {
        // Fill parameters of Init structure in heth handle
        heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
        heth.Init.Speed = ETH_SPEED_10M;
        heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
        // must be a number between Min_Data = 0 and Max_Data = 32
        heth.Init.PhyAddress = 11;
        // MAC Address of used Hardware: must be pointer on an array of 6 bytes
        heth.Init.MACAddr = &uc_MACAddress[0];
        heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
        heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
        heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;

        HAL_ETH_Init(&heth);

        // API to initialize the Ethernet peripheral (MAC, DMA, ...)
        HAL_ETH_Init(&heth);

        // Init the low level hardware : GPIO, CLOCK, NVIC. */
        HAL_ETH_MspInit(&heth);
    }

    void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
    {
        GPIO_InitTypeDef GPIO_InitStruct = {0};
        if (heth->Instance == ETH)
        {
            /* ETH clock enable */
            __HAL_RCC_ETH_CLK_ENABLE();

            __HAL_RCC_GPIOC_CLK_ENABLE();
            __HAL_RCC_GPIOA_CLK_ENABLE();
            __HAL_RCC_GPIOB_CLK_ENABLE();
            __HAL_RCC_GPIOG_CLK_ENABLE();

            /**ETH GPIO Configuration
            PC1     ------> ETH_MDC
            PA1     ------> ETH_REF_CLK
            PA2     ------> ETH_MDIO
            PA7     ------> ETH_CRS_DV
            PC4     ------> ETH_RXD0
            PC5     ------> ETH_RXD1
            PB13     ------> ETH_TXD1
            PG11     ------> ETH_TX_EN
            PG13     ------> ETH_TXD0
            */
            GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
            HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

            GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

            GPIO_InitStruct.Pin = GPIO_PIN_13;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
            HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

            GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_13;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
            HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

            /* ETH interrupt Init */
            HAL_NVIC_SetPriority(ETH_IRQn, 5, 0);
            HAL_NVIC_EnableIRQ(ETH_IRQn);
        }
    }

    void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth)
    {
        if (heth->Instance == ETH)
        {
            /* Peripheral clock disable */
            __HAL_RCC_ETH_CLK_DISABLE();

            /**ETH GPIO Configuration
            PC1     ------> ETH_MDC
            PA1     ------> ETH_REF_CLK
            PA2     ------> ETH_MDIO
            PA7     ------> ETH_CRS_DV
            PC4     ------> ETH_RXD0
            PC5     ------> ETH_RXD1
            PB13     ------> ETH_TXD1
            PG11     ------> ETH_TX_EN
            PG13     ------> ETH_TXD0
            */
            HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5);
            HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7);
            HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13);
            HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13);

            /* ETH interrupt Deinit */
            HAL_NVIC_DisableIRQ(ETH_IRQn);
        }
    }


#ifdef __cplusplus
}
#endif

extern "C" void create_task_tcp_main()
{
    g_print("Creating TCP thread\n");

    xTaskCreate(
        task_tcp_main,
        "tcp_main",
        configMINIMAL_STACK_SIZE * 2,
        NULL,
        3,
        NULL);
}

extern "C" void task_tcp_main(void *pvParameters)
{
    g_print("\nStart TCP thread\n");

    // Variable to hold the created socket
    Socket_t xListeningSocket, xConnectedSocket;
    struct freertos_sockaddr xClient, xBindAddress;
    socklen_t xSize = sizeof(xClient);
    static const TickType_t xReceiveTimeOut = portMAX_DELAY; // pdMS_TO_TICKS(10);
    const BaseType_t xBacklog = 2;

    // Attempt to open the socket
    xListeningSocket = FreeRTOS_socket(
        FREERTOS_AF_INET4,    // IPv4
        FREERTOS_SOCK_STREAM, // sock stream for tcp
        FREERTOS_IPPROTO_TCP  // TCP protocol
    );

    // change setsockopt here if needed

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

    // configASSERT(xListeningSocket != FREERTOS_INVALID_SOCKET);
    // Check the socket was created
    if (xListeningSocket != FREERTOS_INVALID_SOCKET)
    {
        // Set the listening port to 10000
        memset(&xBindAddress, 0, sizeof(xBindAddress));
        xBindAddress.sin_port = (uint16_t)10000;
        xBindAddress.sin_port = FreeRTOS_htons(xBindAddress.sin_port);
        xBindAddress.sin_family = FREERTOS_AF_INET4;

        // 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 8.
        FreeRTOS_listen(xListeningSocket, xBacklog);

        for (;;)
        {
            // Wait for incoming connection
            xConnectedSocket = FreeRTOS_accept(xListeningSocket, &xClient, &xSize);

            if (xConnectedSocket != FREERTOS_INVALID_SOCKET)
            {
                // Spawn a RTOS task to handle the connection
                xTaskCreate(
                    task_server_connection_instance,
                    "Echo",
                    configMINIMAL_STACK_SIZE * 4,
                    (void*)xConnectedSocket,
                    tskIDLE_PRIORITY+4,
                    NULL);
            }
        }
    }
    else
    {
        // Should never reach here
        g_print("Issue creating TCP socket\n");
    }
}

#define BUFFER_SIZE 512
extern "C" void task_server_connection_instance(void *pvParameters)
{
    g_print("Connected to Server\n");
    Socket_t xSocket;
    static char rx_data[BUFFER_SIZE];
    BaseType_t bytes_received;

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

    for (;;)
    {
        // Receive another block of data into the rx_data buffer
        bytes_received = FreeRTOS_recv(xSocket, &rx_data, BUFFER_SIZE, 0); // FREERTOS_MSG_DONTWAIT);

        if (bytes_received > 0)
        {
            // Data was received, process it
            process_data(rx_data, bytes_received);
        }
        else if (bytes_received == 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). */
    uint8_t count = 0;
    while (FreeRTOS_recv(xSocket, &rx_data, 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(500));
        count++;
        /* Note - real applications should implement a timeout here, not just
           loop forever. */
        if (count > 20)
        {
            break;
        }
    }

    /* 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 process_data(char *data, BaseType_t bytes_rx)
{
    g_print("We received data!\n");
}

nuclo_wrong_bytes_received.zip (939 Bytes)
ping_and_connect_good_send_data_bad.zip (1.2 KB)

I bumped your forum status up a bit - see if you can upload the pcap file now.

@rtel Sorry, it still won’t let me upload.

@rtel looks like I’m now able to upload it. I’ve attached to the original post, thanks.

Hi @sensor_guru,
The value 0xfffffff4 represents -pdFREERTOS_ERRNO_ENOMEM , which prvRECVWait returns when unable to allocate memory for the TCP stream buffer. For helpful advice on this issue, please see: FreeRTOS TCP/IP pdFREERTOS_ERRNO_ENOMEM (Nucleo-F767Zi).

Thank you.

2 Likes

@ActoryOu Thanks for the link to the other thread, it helped resolve my problem. I implemented the Malloc failed hook which turned out to be the problem. Increasing the size of the Heap resolved the issue.

Thanks for reporting back! I’m glad that helps!