# 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 } ```