Quick start with FreeRTOS(smp) on Raspberry Pi Pico
Why FreeRTOS? FreeRTOS is an open source, cloud-neutral, real-time operating system supporting many processor architectures, and…
Quick start with FreeRTOS(smp) on Raspberry Pi Pico
Why FreeRTOS? FreeRTOS is an open source, cloud-neutral, real-time operating system supporting many processor architectures, and additionally it supports SMP for task scheduling. FreeRTOS for AWS libraries implement clients for AWS IoT specific value add cloud services, including over the air updates (OTA) and AWS IoT Analytics.
Why Raspberry Pi Pico? The Raspberry Pi Pico is a low-cost, high-performance microcontroller board featuring the RP2040 (or new RP2350) dual-core ARM Cortex-M0+/M33 chip. It offers 264KB/520KB SRAM, 2MB+ onboard flash, and 26 multi-function GPIO pins. And this comes with very detailed documentation and community support. Although, for wireless connectivity you need to choose W models.
Step 1: Set Up the Raspberry Pi Pico Development Environment, Before integrating FreeRTOS, we must have a functional C/C++ development environment for the Raspberry Pi Pico. Follow the official instructions in the “Getting Started With Pico” documentation to install the necessary tools, including the GCC ARM compiler, CMake and the Pico SDK. We should now have PICO_SDK_PATH exported to environment, along with PICO_PLATFORM and PICO_BOARD variables, appropriately pointing to platform and board information.
Step 2: Set up FreeRTOS, Since we want to experiment with SMP, we will use SMP branch of FreeRTOS kernel.
git clone -b smp https://github.com/FreeRTOS/FreeRTOS-Kernel - recurse-submodules
Now, set the FREERTOS_KERNEL_PATH environment variable appropriately. Alternatively, we can integrate FreeRTOS as git submodule in the project.
Step 3: Obligatory Blink application, Lets create a small application to blink leds, refer to the connection diagram.

Connection Diagram
We will connect GPIO 1, 5 and 9 to LEDs, along 220 Ohm resistors for current limiting purpose. And here is a small application to control each LED in separate task.
#include <stdio.h>
#include "pico/stdlib.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#define PICO_GP1 1
#define PICO_GP5 5
#define PICO_GP9 9
TaskHandle_t Task1;
TaskHandle_t Task2;
TaskHandle_t Task3;
SemaphoreHandle_t __print_mutex;
void __vSafePrint(char *out) {
xSemaphoreTake(__print_mutex, portMAX_DELAY);
puts(out);
xSemaphoreGive(__print_mutex);
}
//Task1code: blinks an LED every 1500 ms
void Task1code( void * pvParameters ){
char printBuf[48];
for(;;){
sprintf(printBuf, "Task1 running on core: %d, Tick: %d\n", portGET_CORE_ID(), xTaskGetTickCount());
__vSafePrint(printBuf);
gpio_put(PICO_GP1, 1);
vTaskDelay(1500);
gpio_put(PICO_GP1, 0);
vTaskDelay(1500);
}
}
//Task2code: blinks an LED every 700 ms
void Task2code( void * pvParameters ){
char printBuf[32];
for(;;){
sprintf(printBuf, "Task2 running on core: %d, Tick: %d\n", portGET_CORE_ID(), xTaskGetTickCount());
__vSafePrint(printBuf);
gpio_put(PICO_GP5, 1);
vTaskDelay(700);
gpio_put(PICO_GP5, 0);
vTaskDelay(700);
}
}
//Task3code: blinks an LED every 100 ms
void Task3code( void * pvParameters ){
char printBuf[32];
for(;;){
sprintf(printBuf, "Task3 running on core: %d, Tick: %d\n", portGET_CORE_ID(), xTaskGetTickCount());
__vSafePrint(printBuf);
gpio_put(PICO_GP9, 1);
vTaskDelay(100);
gpio_put(PICO_GP9, 0);
vTaskDelay(100);
}
}
void __pin_setup() {
stdio_init_all();
__print_mutex = xSemaphoreCreateMutex();
gpio_init(PICO_GP1);
gpio_set_dir(PICO_GP1, GPIO_OUT);
gpio_init(PICO_GP5);
gpio_set_dir(PICO_GP5, GPIO_OUT);
gpio_init(PICO_GP9);
gpio_set_dir(PICO_GP9, GPIO_OUT);
}
void main() {
__pin_setup();
xTaskCreate(Task1code, "Blink Task 1", 128, NULL, 1, &Task1);
vTaskCoreAffinitySet(Task1, (1 << 0)); //core 1
xTaskCreate(Task2code, "Blink Task 2", 128, NULL, 2, &Task2);
vTaskCoreAffinitySet(Task2, (1 << 1)); //core 2
xTaskCreate(Task3code, "Blink Task 3", 128, NULL, 2, &Task3);
vTaskCoreAffinitySet(Task2, (1 << 1)); //core 2
vTaskStartScheduler();
}
Further we need to setup project CMake and FreeRTOS configurations, Raspberry Pi Pico C/C++ SDK uses CMake build system. Here is CmakeLists.txt file to get your project started,
cmake_minimum_required(VERSION 3.30)
# Pull in SDK (must be before project)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
# Pull in FreeRTOS
include($ENV{FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake)
message(DEBUG "FREERTOS_KERNEL_PATH is ${FREERTOS_KERNEL_PATH}")
project(app C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Initialize the SDK
pico_sdk_init()
add_executable(rtos-blink main.c)
target_include_directories(rtos-blink PRIVATE ${CMAKE_CURRENT_LIST_DIR})
# pull in common dependencies
target_link_libraries(rtos-blink pico_stdlib FreeRTOS-Kernel FreeRTOS-Kernel-Heap4)
# enable usb output, disable uart output
pico_enable_stdio_usb(rtos-blink 1)
pico_enable_stdio_uart(rtos-blink 0)
# create map/bin/hex/uf2 file etc.
pico_add_extra_outputs(rtos-blink)
Following FreeRTOS configration is extended from FreeRTOSConfig_examples_common.h, found in pico-examples/ repo, with some additional notes.
/*
* FreeRTOS V202107.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
//XXX adding config options from arduino-pico, marked in comment as AP:
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0 // AP: 1, default 0
#define configUSE_TICK_HOOK 0 // AP: 1, default 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 8 ) // AP: ( 8 ), default 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0 // AP: 1, default 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE ( (size_t) (164 * 1024 ) ) // AP: ( ( size_t ) ( 164 * 1024 ) ), default (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0 // AP: 2, default 0
#define configUSE_MALLOC_FAILED_HOOK 0 // AP: 1, default 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 // AP: 1, default 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0 // AP: 1
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0 // AP: 1, default 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1 // AP: 2
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) // AP: 2
#define configTIMER_QUEUE_LENGTH 5 // AP: 5, default 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* following are from arduino-pico */
#define configPRIO_BITS 3 /* 8 priority levels */
#define configENABLE_MPU 0
#define configENABLE_TRUSTZONE 0
#define configRUN_FREERTOS_SECURE_ONLY 1
#define configENABLE_FPU 1
/* Interrupt nesting behaviour configuration. */
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7 //only in AP
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 //only in AP
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) //only in AP
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) //only in AP, and RP2350: 16
//#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
/* SMP port only */
#define configNUM_CORES 2
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1 // AP: 1, 0 : same prio task run simultaneously, 1: different prio tasks run simultaneously
#define configUSE_CORE_AFFINITY 1
/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#define LIB_PICO_MULTICORE 1 //default 0
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x) // AP: not defined
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */
Now your project directory should look as follows,
rtos-blink
├── build/
├── CMakeLists.txt
├── FreeRTOSConfig.h
├── main.c
└── readme
Let’s build,
#configure
cmake -B build -S .
#build
make -C build
Use the uf2 file will be located in build directory to transfer to Pico. You should see blinking LEDs.
Step 4: What next?
- FreeRTOS profiling,
In future we will explore basic profiling using configuration options
configGENERATE_RUN_TIME_STATSand tracing using third-party tool “Percepio View”. - Explore FreeRTOS on other micro-controllers, Most notably ESP32 series micro-controllers from Espressif, as the development enviornment is built on top of FreeRTOS.
메타데이터
- post_id
- ae1d60d7f6da
- slug
- quick-start-with-freertos-smp-on-raspberry-pi-pico-ae1d60d7f6da
- url
- https://medium.com/@ratnaraj.mirgal/quick-start-with-freertos-smp-on-raspberry-pi-pico-ae1d60d7f6da
- canonical_url
- https://medium.com/@ratnaraj.mirgal/quick-start-with-freertos-smp-on-raspberry-pi-pico-ae1d60d7f6da
- author_url
- https://medium.com/@ratnaraj.mirgal
- status
- ok
- fetched_at
- 2026-07-13 06:23:13