# Setup and Compile FreeRTOS for Raspberry Pi Pico
Following guide is tested with Raspberry Pi Pico W.
1. Clone FreeRTOS source
``` shell
git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git
cd FreeRTOS-Kernel
git submodule update --init
```
2. Use official Raspberry Pi Pico VSCode extension to create a project.
When creating the project, choose **the correct board type** and check `Console over USB` if you want to use UART over USB.
3. Navigate to [FreeRTOS-Kernel/RP2040](https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/main/portable/ThirdParty/GCC/RP2040), download `FreeRTOS_Kernel_import.cmake` and place in the root of the project.
4. Insert following block into `CMakeLists.txt` just below `pico_sdk_init()`.
``` cmake
# Tell FreeRTOS which port (RP2040) and heap to use
set(FREERTOS_PORT GCC_RP2040 CACHE STRING "")
set(FREERTOS_HEAP 4 CACHE STRING "")
# Point the import script at your kernel checkout
set(FREERTOS_KERNEL_PATH "/home/hyy/Documents/pico/FreeRTOS-Kernel" CACHE PATH "")
# NEW: define where FreeRTOSConfig.h is
add_library(freertos_config INTERFACE)
target_include_directories(freertos_config SYSTEM
INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
include(FreeRTOS_Kernel_import.cmake)
```
- Modify `FREERTOS_KERNEL_PATH` to your actual path to FreeRTOS-Kernel folder.
5. Add `FreeRTOS-Kernel` and `FreeRTOS-Kernel-Heap4` to `target_link_libraries()` in `CMakeLists.txt`
``` cmake
# Add any user requested libraries
target_link_libraries(rtos_example
pico_stdlib
pico_cyw43_arch_none
FreeRTOS-Kernel
FreeRTOS-Kernel-Heap4
)
```
6. Place `FreeRTOSConfig.h` under the root of the project.
Example for Pico W:
``` c
#pragma once
/* ====== Core kernel features ====== */
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( 125000000UL ) /* default Pico clock */
#define configTICK_RATE_HZ ( 1000 )
#define configMAX_PRIORITIES ( 7 )
#define configMINIMAL_STACK_SIZE ( 256 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024 ) ) /* heap_4 */
/* ====== SMP on RP2040 (2 cores) ====== */
#define configNUMBER_OF_CORES 2
#define configRUN_MULTIPLE_PRIORITIES 1
/* ====== Queues/semaphores/timers ====== */
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH ( 1024 )
/* ====== API functions we want ====== */
#define INCLUDE_vTaskDelay 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_xTimerPendFunctionCall 1
/* ====== Interrupt priorities (Cortex-M0+) ====== */
#define configPRIO_BITS 2
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* ====== Assert hook to help debugging ====== */
void vAssertCalled( const char * file, int line );
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled(__FILE__, __LINE__)
#define configUSE_PASSIVE_IDLE_HOOK 0
#define configUSE_CORE_AFFINITY 1
```
7. Edit the main c file to run FreeRTOS.
Example for Pico W:
``` c
#include <stdio.h>
#include "pico/stdlib.h"
#include "FreeRTOS.h"
#include "task.h"
#include "pico/cyw43_arch.h"
/* Assert handler declared in FreeRTOSConfig.h */
void vAssertCalled(const char* file, int line) {
// Print to USB-CDC if enabled; then halt
printf("ASSERT: %s:%d\n", file, line);
taskDISABLE_INTERRUPTS();
for(;;);
}
// Perform initialisation
int pico_led_init(void) {
#if defined(PICO_DEFAULT_LED_PIN)
// A device like Pico that uses a GPIO for the LED will define PICO_DEFAULT_LED_PIN
// so we can use normal GPIO functionality to turn the led on and off
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
return PICO_OK;
#elif defined(CYW43_WL_GPIO_LED_PIN)
// For Pico W devices we need to initialise the driver etc
return cyw43_arch_init();
#endif
}
// Turn the led on or off
void pico_set_led(bool led_on) {
#if defined(PICO_DEFAULT_LED_PIN)
// Just set the GPIO on or off
gpio_put(PICO_DEFAULT_LED_PIN, led_on);
#elif defined(CYW43_WL_GPIO_LED_PIN)
// Ask the wifi "driver" to set the GPIO on or off
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
#endif
}
static void vBlinkTask(void *pv) {
int rc = pico_led_init();
hard_assert(rc == PICO_OK);
while (1) {
pico_set_led(true);
vTaskDelay(pdMS_TO_TICKS(250));
pico_set_led(false);
vTaskDelay(pdMS_TO_TICKS(250));
}
}
static void vHelloTask(void *pv) {
while (1) {
printf("Hello from FreeRTOS on core %d!\n", get_core_num());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static void vHelloTask2(void *pv) {
while (1) {
printf("Hello from FreeRTOS on core %d!\n", get_core_num());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
const UBaseType_t core0_mask = 1 << 0; // core 0
const UBaseType_t core1_mask = 1 << 1; // core
stdio_init_all(); // enable printf over USB (you already turned on USB stdio in CMake)
xTaskCreate(vBlinkTask, "blink", 512, NULL, tskIDLE_PRIORITY + 1, NULL);
xTaskCreateAffinitySet(vHelloTask, "hello", 512, NULL, tskIDLE_PRIORITY + 1, core0_mask, NULL);
xTaskCreateAffinitySet(vHelloTask2, "hello2", 512, NULL, tskIDLE_PRIORITY + 1, core1_mask, NULL);
vTaskStartScheduler(); // hands control to FreeRTOS (never returns)
for(;;); // safety
}
```