FreeRTOS+TCP - Sending multiple UDP packets

Hello everyone,

Im trying to setup some code that handle multiple clients that send packets to a server on the STM32.

I tried to use this code example of @tony-josi-aws GitHub - tony-josi-aws/STM32_Nucleo_H723ZG_FreeRTOS_TCP

And changed the tasks to be like in here:

My test case is as follow:

  • Send X packets from a python script to the ST

And after 20 packets (also depends on the size of the packet) the ST lose packets.

I tried to inccrease this:

FreeRTOIPConfig.h

/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that
are available to the IP stack. The total number of network buffers is limited
to ensure the total amount of RAM that can be consumed by the IP stack is capped
to a pre-determinable value. */
#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60

Any idea of how to handle packets faster or how to handle this situation?

It would be good if you can share some code snippet showing how you handle the client connection. It may also be a good idea to get the non-zero copy working first before moving on to zero copy.

Normally, the STM32H7 is very fast in networking. If your application is running out of ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, it will issue warnings, and when it runs out of buffers, the program will get an assert.

I recommend to replace Python with something else: either ncat, a native networking application, or a Go script.

It is on my list to test the UDP demo on a STM32H7, and I will report back here.

@aggarg wrote:

It would be good if you can share some code snippet showing how you handle the client connection

Yes please, show some related source code, especially how you handle the sockets.

Hi thx for your response.

I tried to handle the clients like the example of tony on the nucleo-h723g:

  • Im creating 1 task for the server:

static void vUDPReceivingUsingZeroCopyInterface( void *pvParameters )

{

int32_t lBytes;

uint8_t *pucUDPPayloadBuffer;

struct freertos_sockaddr xClient, xBindAddress;

uint32_t xClientLength = sizeof( xClient ), ulIPAddress;

Socket_t xListeningSocket;

/* Attempt to open the socket. */

xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET,

                                      /\* FREERTOS_AF_INET6 to be used for IPv6 \*/

                                   FREERTOS_SOCK_DGRAM, 

                                      /\*FREERTOS_SOCK_DGRAM for UDP.\*/

                                   FREERTOS_IPPROTO_UDP );

/* Check the socket was created. */

configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );

/* Bind to port 10000. */

memset( &xBindAddress, 0, sizeof(xBindAddress) );

xBindAddress.sin_port = FreeRTOS_htons( 10000 );

xBindAddress.sin_family = FREERTOS_AF_INET4; /* FREERTOS_AF_INET6 to be used for IPv6 */

FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

for( ;; )

{

   /\* Receive data from the socket. ulFlags has the zero copy bit set

      (FREERTOS_ZERO_COPY) indicating to the stack that a reference to the

      received data should be passed out to this RTOS task using the second

      parameter to the FreeRTOS_recvfrom() call. When this is done the

      IP stack is no longer responsible for releasing the buffer, and

      the RTOS task \*\*must\*\* return the buffer to the stack when it is no longer

      needed. By default the block time is portMAX_DELAY but it can be

      changed using FreeRTOS_setsockopt(). \*/

   lBytes = FreeRTOS_recvfrom( xListeningSocket,

                               &pucUDPPayloadBuffer,

                               0,

                               FREERTOS_ZERO_COPY,

                               &xClient,

                               &xClientLength );

   if( lBytes > 0 )

   {

       /\* Data was received and can be processed here. \*/

   }

   if( lBytes >= 0 )

   {

       /\* The receive was successful so this RTOS task is now responsible for

          the buffer. The buffer \*\*must\*\* be freed once it is no longer

          needed. \*/

       /\*

        \* The data can be processed here.

        \*/

       /\* Return the buffer to the TCP/IP stack. \*/

       FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );

   }

}

}

And i also tried the one without the zero-copy.

I tried to run on debug and im seeing that the pvPortMalloc() function is failing when trying to get a network buffer and as a Result the following function get called:

void vApplicationMallocFailedHook( void )

{

/\* If configUSE_MALLOC_FAILED_HOOK is set to 1 then this function will

 \* be called automatically if a call to pvPortMalloc() fails.  pvPortMalloc()

 \* is called automatically when a task, queue or semaphore is created. \*/

for( ;; );

}

/*-----------------------------------------------------------*/

The thing is im not running out of space of network buffers, im using the logging of vPrintResourceStats and im see that the heap is not full and there are still network buffers that can be allocated.

Any ideas what can cause it?

If your checking the demo it would be great if there will be a demo with newer releases with new Networkinterface.c because In @tony-josi-aws demo its using version 2.3.2.

Thanks alot for your help guys.

I must say that the features tested in mentioned demos haven’t changed much in the last 5 years. The most important thing that did change is the introduction of interfaces and end-points.

But yes, I am reviewing all older demos and they will be updated.

If you have in-ciruit debugging, can you put a break in the function vApplicationMallocFailedHook()? I would be curious about the call-stack to see from where the allocation was done.

Are you using BufferAllocation_1.c or BufferAllocation_2.c?

The advantage of BufferAllocation_1 is that the buffer space is allocated statically, thus causing less surprises.

PS. check the desired number of ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS. 60 buffers is a lot. Calling vPrintResourceStats() may be useful: it shows the lowest amount ever.

Thanks waiting for your update.

Im sometimes getting the Malloc error and sometimes the following stack frame:

1.pxPortInitializeStack()

2.prvEMACHandlerTask()

3.prvNetworkInterfaceInput()

4.pxGetNetworkBufferWithDescriptor()

And inside 4. Im getting that pxReturn ==NULL And the assert of ipTraceFailed_To_obtain_network_buffer() is called.

Im using Buffer Allocation scheme 2.

If you could provide a simple udp server example for the NUCLEO-H743 or something similar that works and update here it would be amazing.

Thanks alot for your help and support.

Waiting for an update🙏

This means that this pvPortMalloc call is failing - FreeRTOS-Plus-TCP/source/portable/BufferManagement/BufferAllocation_2.c at main · FreeRTOS/FreeRTOS-Plus-TCP · GitHub. Which FreeRTOS heap are you using? If you are using heap 4, you can fix that by increasing configTOTAL_HEAP_SIZE in your FreeRTOSConfig.h.