How-To: FreeRTOS on Raspberry Pi Pico
Background
The Raspberry Pi Pico (RP2040) is well supported by FreeRTOS. This post will take the example blink project and demonstrate how to convert it to FreeRTOS.
Get the files from the repo.
Steps
Create the blink example project.

Create include folder and create the FreeRTOSConfig.h. The file is too big to display here so copy it from the repo. For simplicity the project only configures 1 CPU core.

Modify the CMakeLists.txt to fetch FreeRTOS.
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Set up FreeRTOS here
include(FetchContent)
FetchContent_Declare(
freertos_kernel
GIT_REPOSITORY https://github.com/FreeRTOS/FreeRTOS-Kernel.git
GIT_TAG
V11.2.0 #Note: Best practice to use specific git-hash or tagged version
)
add_library(freertos_config INTERFACE)
target_include_directories(freertos_config SYSTEM INTERFACE include)
target_compile_definitions(freertos_config INTERFACE projCOVERAGE_TEST=0)
set(FREERTOS_HEAP "4" CACHE STRING "" FORCE)
# Select the cross-compile PORT
if(CMAKE_CROSSCOMPILING)
set(FREERTOS_PORT "GCC_RP2040" CACHE STRING "" FORCE)
endif()
FetchContent_MakeAvailable(freertos_kernel)
include(
${freertos_kernel_SOURCE_DIR}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake
)
#end FreeRTOS
# Add executable. Default name is the project name, version 0.1
add_executable(blink blink.c)
# pull in common dependencies
target_link_libraries(
blink
pico_stdlib
FreeRTOS-Kernel
FreeRTOS-Kernel-Heap4
freertos_config
)
Then modify blink.c. This shows very basic example of creating a task to blink the LED. Instead of the sleep functions used in the original example, this code uses vTaskDelay which yields the task for the specified time and lets other task run.
#include "FreeRTOS.h"
#include "task.h"
void led_handler(void * parameter)
{
while (true) {
pico_set_led(true);
vTaskDelay(pdMS_TO_TICKS(LED_DELAY_MS));
pico_set_led(false);
vTaskDelay(pdMS_TO_TICKS(LED_DELAY_MS));
}
}
int main()
{
int rc = pico_led_init();
hard_assert(rc == PICO_OK);
xTaskCreate(led_handler, "led_handler", 1024, NULL, 1, NULL);
/* Start the RTOS scheduler. */
vTaskStartScheduler();
/* If all is well, the scheduler will now be running, and the following
line will never be reached. If the following line does execute, then
there was insufficient FreeRTOS heap memory available for the idle and/or
timer tasks to be created. */
for (;;);
}
Now the project should build and run.
Conclusion
This demonstrates converting the blink example to a simple FreeRTOS application. From here more advanced FreeRTOS topics can be explored.