FreeRTOS task create/delete (with NXP's RT1052 USB)

I’m running on the RT1052 w/ FreeRTOS Kernel V10.2.1.

If I use the FreeRTOS USB demo for this device, everything works, but the demo only creates a task, and inits USB (no task delete).

If I want to shut down USB, by doing the reverse of the setup seemed to be the obvious way to do things, it works for a while…, but this appears to be leading to memory corruption / over allocation if I repeatedly delete and re-create the tasks.

In my own project, I eventually get an assertion when trying to delete the task:

A memory watchpoint on this (in FreeRTOS heap space) breaks on USB_DeviceStop().

I port this to a basic example (creates & deletes USB tasks when the user hits the button):
The example fails @ xTaskCreate when repeatedly creating / deleting tasks. While this seems different from what would cause the code to assert at

	configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );

possibly the same source cause - over allocation???

Example tested on an RT1052 Arch Seeed board: https://github.com/andrewrt/rt1050_cdc_vcom_freertos

Does anyone have insight into the NXP USB port of FreeRTOS and proper task deletion?

Or is this something more basic w/ the FreeRTOS kernel - like I need to somehow wait and confirm a task was completely deleted before that memory is available again?

I’m afraid it is unlikely anybody here will know the specifics of the demos provided by NXP.

From your description it sounds like you are not returning memory to the heap when the task is deleted and you are eventually running out of heap space. Further, that particular assert being hit means you are trying to free memory that was either never allocated in the first place (do you check all allocates succeed before using the memory?) or you are freeing a block of memory that has been corrupted.

Do you have configASSERT() defined, stack overflow detection on, and the malloc failed hook implemented, as described on this page? https://www.freertos.org/FAQHelp.html

1 Like

Hi @rtel,
Thanks for the quick response!

From your description it sounds like you are not returning memory to the heap when the task is deleted and you are eventually running out of heap space.

Agreed - the tough part is, since I’m calling code from either the NXP SDK USB stack or FreeRTOS stack, the code goes pretty deep and is a little tough to follow. From what you’re saying - sounds like this is purely NXP code, not FreeRTOS on their deinit stuff.

Further, that particular assert being hit means you are trying to free memory that was either never allocated in the first place (do you check all allocates succeed before using the memory?) or you are freeing a block of memory that has been corrupted.

Do you have configASSERT() defined, stack overflow detection on, and the malloc failed hook implemented, as described on this page? https://www.freertos.org/FAQHelp.html

For the FreeRTOS config, I already had stackoverflow & configAssert defined as per the below. I will test wth vApplicationMallocFailedHook this week.

#define configCHECK_FOR_STACK_OVERFLOW          2

/* Define to trap errors during development. */
#define configASSERT(x) if((x) == 0) {taskDISABLE_INTERRUPTS(); for (;;);}

and then in main, as the debugger never ends up stuck in this while(1), assuming it’s not stack overflow.


void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) {
  while (1) {
    /* my code. Prints stuff directly to the console*/
  }
}

My only use of malloc follows this flow, from one task:

          cmd_buf = pvPortMalloc(cmd_size);
          if (cmd_buf != NULL) {
            memcpy(cmd_buf, static_buff, cmd_size);
            cmd_event.json_str_ptr = cmd_buf;
            cmd_event.size = cmd_size;
            x_status = xQueueSendToBack(x_queue, &cmd_event, 0);
            if (x_status != pdPASS) {
            }
          }

And then from another task,

xStatus = xQueueReceive( x_queue,  &cmd_event, portMAX_DELAY );
    if( xStatus == pdPASS ) {
      if (cmd_event.size > 0){
        consume(cmd_event.json_str_ptr, cmd_event.size);
        vPortFree(cmd_event.json_str_ptr);
      }
    }

Assuming no task starvation, do you see any issue w/ how I’m using pvPortMalloc (in one task), and free in the receiver task?

Thanks again

Your dynamic memory management is ok. Although you should free the buffer not sent successfully even if that shouldn’t happen.
Given that pvPortMalloc and vPortFree are properly implemented.
If you are using a decent GCC tool chain with newlib you could also implement the malloc un/locks and directly use malloc/free if you’re using the C-library (newlib) heap implementation. Or do you use one of the FreeRTOS heap implementations ?
I afraid you have to trace the memory management of the USB stack/task.
But first you should check that there are thread-safe (wrapped ?) malloc/free calls used.

1 Like

thanks for the confirmation @hs2,
I will add the vPortFree @ enqueue failure as advised.

Re malloc:
I’m using the FreeRTOS pvPortMalloc with heap4, but… I am using some external code:

Compiler is arm-none-eabi-gccwith NewlibNano (Auto)

That said, it seems that no matter how many JSON strings I parse, or lvgl UI actions I make, I don’t have issues. Just USB shutdown/startup. I’ll ping NXP directly for some insight on their USB stack and probe in parallel as you and @rtel suggested.

This means it uses the newlib heap which would require that the malloc lock hooks should be provided to be thread-safe e.g. if cJSON API is used in different tasks.
Which allocator is used by the USB stack ? Also plain malloc/free ?
See also http://www.nadler.com/embedded/newlibAndFreeRTOS.html for a good explanation and maybe check your toolchain/newlib version.