Static allocation on RP2040 Pico

I am trying to get FreeRTOS working with static allocation on the Raspberry Pi Pico (RP2040). But for the life of me I just can’t get it working. I believe I’ve set up the FreeRTOSConfig.h correctly.

The problem starts when I call xTaskCreateStatic(). This never returns. Having added lots of printf() statements to track the code execution, it looks like it’s crashing inside vPortEnterCritical().

Has anyone managed to get static allocation working on the RP2040?

Hugo

Can you share your code for xTaskCreateStatic? Does xTaskCreate work for you?

Here is the code that calls xTaskCreateStatic().

int i1 = 0;
int i2 = 0;
int i3 = 0;

void Task1(void* nothing)
{
    printf("Task1\n");
    while(1)
    {
        printf("%d %d %d\n", i1, i2, i3);
        i1++;
        sleep_ms(200);
    }
}

void Task2(void* nothing)
{
    printf("Task2\n");
    while(1)
    {
        i2++;
        sleep_ms(270);
    }
}

#define staticCREATOR_TASK_STACK_SIZE  (configMINIMAL_STACK_SIZE * 2)
#define staticTASK_PRIORITY            ( tskIDLE_PRIORITY + 2 )

void TestTasks()
{
    stdio_init_all();
    sleep_ms(4000);

    printf("\n\nTestTasks()\n");

    static StackType_t stack0[staticCREATOR_TASK_STACK_SIZE ];
    static StackType_t stack1[staticCREATOR_TASK_STACK_SIZE ];

    static StaticTask_t task0, task1;

    TaskHandle_t ret1 = xTaskCreateStatic(Task1, "Task1",
                                          staticCREATOR_TASK_STACK_SIZE,
                                          NULL,
                                          staticTASK_PRIORITY,
                                          (StackType_t*)stack0,
                                          &task0);
  
    // Code never reaches here

    if (ret1 != NULL)   printf("Task 1 created OK\n");
    else                printf("Task 1 failed\n");

    TaskHandle_t ret2 = xTaskCreateStatic(Task2, "Task2",
                                          staticCREATOR_TASK_STACK_SIZE,
                                          NULL, staticTASK_PRIORITY,
                                          (StackType_t*)stack1,
                                          &task1);

    if (ret2 != NULL)   printf("Task 2 created OK\n");
    else                printf("Task 2 failed\n");

    vTaskStartScheduler();

    printf("Shouldn't be here");
    while(1)
    {
        i3++;
        sleep_ms(444);
    }
}

I have not tried using xTaskCreate() because I presume that requires the heap? I am not using a heap.

From your code snippet, and the comment in the code, it looks like execution never returns form the first call to xTaskCreateStatic(). If you step through the function in the debugger how far through does it get. Alternatively, if you pause the debugger after calling xTaskCreateStatic() what is the CPU doing? It might be you have configASSERT() defined and an assert if failing.

Using printf() statements to track progress through the code, it looks like it’s crashing inside vPortEnterCritical().

However, when I run the code several times, it doesn’t always get quite as far as that. Very nearly, but not quite. I’m fairly sure that it’s the portDISABLE_INTERRUPTS(); line that kills it.

void vPortEnterCritical( void )
{
    printf("vPortEnterCritical() 1\n");      // This line usually gets printed
    portDISABLE_INTERRUPTS();
    printf("vPortEnterCritical() 2\n");      // This line never gets printed.
    uxCriticalNesting++;

    __asm volatile ( "dsb" ::: "memory" );
    __asm volatile ( "isb" );
}```

Though it is a long shot, can you give the following modification a try:

int i1 = 0;
int i2 = 0;
int i3 = 0;

void Task1(void* nothing)
{
    printf("Task1\n");
    while(1)
    {
        printf("%d %d %d\n", i1, i2, i3);
        i1++;
        sleep_ms(200);
    }
}

void Task2(void* nothing)
{
    printf("Task2\n");
    while(1)
    {
        i2++;
        sleep_ms(270);
    }
}

#define staticCREATOR_TASK_STACK_SIZE  (configMINIMAL_STACK_SIZE * 2)
#define staticTASK_PRIORITY            ( tskIDLE_PRIORITY + 2 )

void TestTasks()
{
    stdio_init_all();
    sleep_ms(4000);

    printf("\n\nTestTasks()\n");

    static StackType_t stack0[staticCREATOR_TASK_STACK_SIZE ];
    static StackType_t stack1[staticCREATOR_TASK_STACK_SIZE ];

    static StaticTask_t task0, task1;

    TaskHandle_t ret1 = xTaskCreateStatic(Task1, "Task1",
                                          staticCREATOR_TASK_STACK_SIZE,
                                          NULL,
                                          staticTASK_PRIORITY,
                                          &(stack0[ 0 ]),
                                          &task0);
  
    // Code never reaches here

    if (ret1 != NULL)   printf("Task 1 created OK\n");
    else                printf("Task 1 failed\n");

    TaskHandle_t ret2 = xTaskCreateStatic(Task2, "Task2",
                                          staticCREATOR_TASK_STACK_SIZE,
                                          NULL, staticTASK_PRIORITY,
                                          &(stack1[0]),
                                          &task1);

    if (ret2 != NULL)   printf("Task 2 created OK\n");
    else                printf("Task 2 failed\n");

    vTaskStartScheduler();

    printf("Shouldn't be here");
    while(1)
    {
        i3++;
        sleep_ms(444);
    }
}

Are you able to run any example provided by the Pico SDK?

Thanks for the suggestion. Unfortunately, it makes no difference.

I haven’t tried the only statically allocated example, as it seems to be for Win32 ( WIN32-MSVC-Static-Allocation-Only ).

Perhaps I should try modifying it to work in RP2040.

I was also just wondering if anyone had ever got static allocation working on the RP2040?

I think your problem is not related to static allocation. It works and won’t cause strange effects as you described. I think your problem might be related to printf debugging and/or insufficient stack size. printf - family functions usually require quite a lot of stack.
Could you simply provide let’s say 1024 as stack size ?
Do you have a debugger at hand to just step through the code ? That would help a lot.
I’d also strongly recommend to define configASSERT and enable stack checking.
Also printf implementations might require enabled interrupts to send the data via a serial interface. So a printf statement inside vPortEnterCritical with interrupts disabled might cause a deadlock.

One thing I should mention first: I only added all of those printf() statements because it wasn’t working, to try to trace the execution of the code.

Now I have tried three things:

Firstly, I managed to get WIN32-MSVC-Static-Allocation-Only to build for the RP2040. This also fails in the same way. xTaskCreateStatic() does not return.

Back to my own project …
Next, I tried removing all of the printf() statements again. It still doesn’t work.

Lastly, I increased the stack size to 1024, then 2048, then 4096. None of them worked. they all died somewhere inside xTaskCreateStatic() as usual.

This is my CMakeLists.txt file:

cmake_minimum_required(VERSION 3.12)

set(PICO_SDK_PATH "D:/Repositories/My_Project/Code/Pico_ML/pico-sdk")
set(CMAKE_C_FLAGS_DEBUG_INIT "-g3 -Og -Wall -Wextra -DDEBUG -std=c++17")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG_INIT}" CACHE STRING "" FORCE)

include(pico_sdk_import.cmake)

project(My_Project_Computer_01)

pico_sdk_init()


file(GLOB
    FILES 
    src/*.c
    src/*.cpp
    src/*.h
    
    ../My_Project_Shared/FreeRTOS-Kernel/list.c
    ../My_Project_Shared/FreeRTOS-Kernel/queue.c
    ../My_Project_Shared/FreeRTOS-Kernel/tasks.c
    ../My_Project_Shared/FreeRTOS-Kernel/timers.c
    ../My_Project_Shared/FreeRTOS-Kernel/portable/GCC/ARM_CM0/port.c
    )

add_executable(My_Project_Computer_01 ${FILES})

target_include_directories(My_Project_Computer_01
    PRIVATE 
    src
    ../My_Project_Shared
    ../My_Project_Shared/FreeRTOS-Kernel/include    
    ../My_Project_Shared/FreeRTOS-Kernel/portable/GCC/ARM_CM0
    )

add_compile_definitions(__MCUXPRESSO)

target_link_libraries(My_Project_Computer_01
    pico_stdlib
    pico_stdio
    pico_multicore
    hardware_pio
    hardware_i2c
    hardware_dma
    hardware_pwm
    hardware_spi
    hardware_interp
)


pico_add_extra_outputs(My_Project_Computer_01)

pico_enable_stdio_usb(My_Project_Computer_01 1) 
pico_enable_stdio_uart(My_Project_Computer_01 0)

Are you able to run getting started examples here - https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf? Once you are able to do that, can you try using this example - FreeRTOS-Community-Supported-Demos/CORTEX_M0+_RP2040 at 3d475bddf7ac8af425da67cdaa2485e90a57a881 · FreeRTOS/FreeRTOS-Community-Supported-Demos · GitHub?

Thanks for the details ! So you already tried some of the right things… very strange.
Static creation is usually working. There is no magic going on.
It’s a pitty that you can’t step through the code with a debugger to find the underlying problem. But trying a demo as reference is a good idea.

hs2,

I would like to use the debugger, but as far as I understand it, it’s fairly complicated to get it working under Windows. I can just see that as another massive time sink.

Aggarg,

Apart from FreeRTOS, all of my Pico code works fine. I’ve written lots of working code with no problems. The only thing I can’t seem to get working is Static FreeRTOS. I wonder if anyone has this working? Has it actually been tested?

Tonight I’ll go back to trying the example code with a heap, which I’m fairly sure I had working before.

That’s the strange point - it’s widely used since many years (me too) w/o any problem. Hence I guess the problem is something else :thinking:

hs2,

When you say you have used it, do you mean that you have statically allocated FreeRTOS working on the RP2040?

Nope - static allocation in general as it’s not platform/port specific.

Are you able to confirm that the dynamically allocated tasks (i.e. tasks created using xTaskCreate) work for you?

Hi Rocketmagnet,

I am able to run the static allocation example above without problem. This pull request is the modification I made to run the example in FreeRTOS-Community-Supported-Demos.

Example result from uart:

TestTasks()
Task 1 created OK
Task 2 created OK
Task1
Task2
0 0 0
1 1 0
2 2 0
3 3 0
4 3 0
5 4 0
6 5 0
7 6 0
8 6 0
9 7 0
10 8 0
11 9 0
12 9 0
13 10 0
14 11 0

The pico SDK I used to run this demo is v1.4.0.

2e6142b | 2022-06-29 | graham sanderson | SDK 1.4.0 release

Can you also give it a try to see if we can have the same result?

Also share my setup to debug RP2040 in windows.

test_setup

I use another Raspberry Pi as a debug probe to debug RP2040 and run a GDB server on it. Then I can use GDB client in windows to connect to GDB server. If this looks convenient to you, you can reference this blog to setup the Raspberry Pi and connect to RP2040.

3 Likes

Sorry. Just seen this. I’ll give it a go.

Hi Fresh,

Thank you so much for doing this. Looking at your pull request, I can see the important detail that was so difficult to discover. The name of the library I needed is FreeRTOS-Kernel. I guess it seems obvious, but I had tried thing like FreeRTOS-Kernel-Static, and that didn’t work. All of the tutorials I have seen just use FreeRTOS-Kernel-Heap4.

I wonder if it’s worth mentioning this in the documentation for building a static version?

I just had to add functions for vApplicationGetIdleTaskMemory() and vApplicationGetTimerTaskMemory() and now it builds!

Thank you!

1 Like