FreeRTOS Implementation Report for Raspberry Pi Zero 2 W
1. Introduction
This report outlines the process of setting up and integrating FreeRTOS on a Raspberry Pi Zero 2 W (BCM2710A1, Cortex-A53, ARM_AARCH64 ) for a bare-metal
embedded project. The goal was to create a FreeRTOS-based application ( C:\Users\divye\freertos_demo ) that interfaces with GPIO using libbcm2835 ,
adapted for bare-metal operation. The report covers downloading FreeRTOS, integration steps, commands executed, challenges faced, errors encountered, and fixes
applied, culminating in the latest implementation status as of June 23, 2025.
2. Initial Setup and Downloading FreeRTOS
2.1. Objective
Set up the development environment on a Windows system using MSYS2 MinGW64, download FreeRTOS, and prepare the project structure for the Raspberry Pi Zero
2 W.
2.2. Steps and Commands
1. Installed Development Tools:
Installed MSYS2 MinGW64 for a Unix-like environment on Windows.
Installed the GNU Arm Embedded Toolchain ( aarch64-none-elf-gcc ):
pacman -S mingw-w64-x86_64-arm-none-eabi-gcc
Installed CMake, Make, and Git:
pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-make git
Installed OpenOCD for flashing:
pacman -S mingw-w64-x86_64-openocd
2. Downloaded FreeRTOS:
Cloned the FreeRTOS kernel repository:
cd /c/Users/divye
git clone --recurse-submodules https://github.com/FreeRTOS/FreeRTOS-Kernel.git freertos_demo/FreeRTOS-Kernel
This created /c/Users/divye/freertos_demo/FreeRTOS-Kernel , containing the kernel source, including the ARM_AARCH64 port
( portable/GCC/ARM_AARCH64 ).
3. Created Project Directory :
Set up the project structure:
mkdir -p /c/Users/divye/freertos_demo/build
cd /c/Users/divye/freertos_demo
4. Downloaded libbcm2835 :
Cloned the libbcm2835 repository for GPIO access:
cd /c/Users/divye
git clone https://github.com/raspberrypi/bcm2835.git
2.3. Challenges
Toolchain Compatibility: Ensuring the aarch64-none-elf-gcc toolchain was compatible with Cortex-A53 and FreeRTOS required verifying the version (e.g.,
13.2.1).
MSYS2 Path Issues : Windows paths ( C:\ ) needed conversion to Unix-style ( /c/ ) for MSYS2 compatibility.
2.4. Fixes
Installed the latest toolchain via MSYS2.
Used /c/ paths consistently in commands and configurations.
3. Integration of FreeRTOS and libbcm2835
3.1. Objective
Integrate FreeRTOS into the project, configure FreeRTOSConfig.h , patch libbcm2835 for bare-metal use, and set up the build system using CMake.
3.2. Steps and Commands
1. Configured FreeRTOSConfig.h :
Created /c/Users/divye/freertos_demo/FreeRTOSConfig.h with initial settings for the Zero 2 W:
#define configCPU_CLOCK_HZ (500000000) /* Zero 2 W: 500 MHz */
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES (7)
#define configMINIMAL_STACK_SIZE (128)
#define configTOTAL_HEAP_SIZE ((size_t)(15 * 1024))
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0xA0
#define configSTACK_ALIGNMENT 16
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#include "portmacro.h"
Questioned whether to add or replace existing content; instructed to merge with existing defines, retaining others (e.g.,
configSUPPORT_DYNAMIC_ALLOCATION ).
2. Set Up CMake for Project:
Created /c/Users/divye/freertos_demo/CMakeLists.txt :
cmake_minimum_required(VERSION 3.10)
project(freertos_demo C ASM)
set(CMAKE_C_COMPILER /c/arm-gnu-toolchain/bin/aarch64-none-elf-gcc)
set(CMAKE_CXX_COMPILER /c/arm-gnu-toolchain/bin/aarch64-none-elf-g++)
set(CMAKE_ASM_COMPILER /c/arm-gnu-toolchain/bin/aarch64-none-elf-as)
add_executable(freertos_demo
main.c
FreeRTOS-Kernel/tasks.c
FreeRTOS-Kernel/queue.c
FreeRTOS-Kernel/list.c
FreeRTOS-Kernel/portable/GCC/ARM_AARCH64/port.c
FreeRTOS-Kernel/portable/MemMang/heap_4.c
)
target_include_directories(freertos_demo PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/FreeRTOS-Kernel/include
${CMAKE_CURRENT_LIST_DIR}/FreeRTOS-Kernel/portable/GCC/ARM_AARCH64
C:/Users/divye/bcm2835/src
)
target_link_libraries(freertos_demo PRIVATE
C:/Users/divye/bcm2835/src/libbcm2835.a
)
Configured build:
cd /c/Users/divye/freertos_demo/build
cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=/c/arm-gnu-toolchain/bin/aarch64-none-elf-gcc \
-DCMAKE_CXX_COMPILER=/c/arm-gnu-toolchain/bin/aarch64-none-elf-g++ \
-CMAKE_ASM_COMPILER=/c/arm-gnu-toolchain/bin/aarch64-none-elf-as
3. Configured VS Code IntelliSense :
Created /c/Users/divye/freertos_demo/.vscode/c_cpp_properties.json :
{
"configurations": [
{
"name": "Zero2W",
"includePath": [
"${workspaceFolder}/**",
"C:/Users/divye/freertos_demo",
"C:/Users/divye/freertos_demo/FreeRTOS-Kernel/include",
"C:/Users/divye/freertos_demo/FreeRTOS-Kernel/portable/GCC/ARM_AARCH64",
"C:/Users/divye/bcm2835/src",
"C:/arm-gnu-toolchain/aarch64-none-elf/include",
"C:/Users/divye/freertos_demo/FreeRTOS-Kernel/include/freertos"
],
"defines": [],
"compilerPath": "C:/arm-gnu-toolchain/bin/aarch64-none-elf-gcc.exe",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "gcc-arm"
}
],
"version": 4
}
4. Prepared libbcm2835 Build :
Configured libbcm2835 :
cd /c/Users/divye/bcm2835
./configure --host=aarch64-none-elf \
CC="/c/arm-gnu-toolchain/bin/aarch64-none-elf-gcc --specs=nosys.specs" \
AR=/c/arm-gnu-toolchain/bin/aarch64-none-elf-ar \
RANLIB=/c/arm-gnu-toolchain/bin/aarch64-none-elf-ranlib
3.3. Challenges
FreeRTOSConfig.h Placement: Confusion about whether to add or replace content; resolved by merging with existing defines.
libbcm2835 Compatibility: Original bcm2835.c relied on Linux mmap , incompatible with bare-metal FreeRTOS.
IntelliSense Red Underlines: VS Code showed red underlines under #include "FreeRTOS.h" and #include "task.h" in bcm2835.c .
3.4. Errors and Fixes
1. Error: Red underlines in VS Code for FreeRTOS.h and task.h in bcm2835.c .
Cause: IntelliSense couldn’t find FreeRTOS headers due to missing include paths.
Fix: Updated c_cpp_properties.json with FreeRTOS paths and refreshed IntelliSense ( Ctrl+Shift+P > C/C++: Refresh ).
2. Error: make failed with bcm2835.c:24: fatal error: FreeRTOS.h: No such file or directory .
Cause: bcm2835 Makefile lacked FreeRTOS include path.
Fix: Re-ran ./configure with CFLAGS :
./configure --host=aarch64-none-elf \
CC="/c/arm64-none-elf-gcc/bin/aarch64-none-elf-gcc --specs=nosys.specs" \
AR="/c/arm-gnu-toolchain/bin/aarch64-none-elf-ar" \
RANLIB="/c/arm-gnu-toolchain/bin/aarch64-none-elf-ranlib" \
CFLAGS="-I/c/Users/divye/freertos_demo/FreeRTOS-Kernel/include"
3. Error: make failed with FreeRTOS.h:58: fatal error: FreeRTOSConfig.h: No such file or directory .
Cause: FreeRTOSConfig.h in /c/Users/divye/freertos_demo wasn’t included in bcm2835 build paths.
Fix: Updated ./configure with additional path:
CFLAGS="-I/c/Users/divye/freertos_demo/FreeRTOS-Kernel/include -I/c/Users/divye/freertos_demo"
4. Error: make failed with portmacro.h:198: error: #error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting and other errors in bcm2835.c
( MAP_FAILED , nanosleep , mapmem ).
Cause:
FreeRTOSConfig.h lacked configUNIQUE_INTERRUPT_PRIORITIES and task.h for TaskHandle_t .
bcm2835.c wasn’t fully patched to remove Linux dependencies ( mmap , nanosleep ).
Fix:
Updated FreeRTOSConfig.h :
#include "task.h"
#define configUNIQUE_INTERRUPT_PRIORITIES 16
Patched bcm2835.c :
Replaced includes and globals:
#include "FreeRTOS.h"
#include "task.h"
#define BCM2835_PERI_BASE 0x3F000000
volatile uint32_t *bcm2835_peripherals = (volatile uint32_t *)0x3F000000;
volatile uint32_t *bcm2835_gpio = (volatile uint32_t *)0x3F200000;
Replaced delays:
void bcm2835_delay(unsigned int millis) {
vTaskDelay(millis / portTICK_PERIOD_MS);
}
void bcm2835_delayMicroseconds(uint64_t micros) {
vTaskDelay((micros / 1000) / portTICK_PERIOD_MS);
}
Commented out mapmem and unmapmem .
Simplified bcm2835_init and bcm2835_close :
int bcm2835_init(void) {
if (!bcm2835_peripherals) return 0;
bcm2835_gpio = bcm2835_peripherals + 0x200000 / 4;
return 1;
}
int bcm2835_close(void) {
return 1;
}
4. Latest Implementation Status
4.1. Current State
FreeRTOS Configuration: FreeRTOSConfig.h is set up with required defines for Cortex-A53, including configUNIQUE_INTERRUPT_PRIORITIES and task.h
for stack overflow hooks.
libbcm2835: Patched to use direct register access and FreeRTOS delays, but not yet successfully compiled due to the latest errors.
Project Build : The main project ( freertos_demo ) is configured with CMake, but compilation depends on a successful libbcm2835 build.
IntelliSense: Red underlines resolved via c_cpp_properties.json .
4.2. Pending Tasks
Resolve libbcm2835 Compilation:
Re-run ./configure with all include paths:
cd /c/Users/divye/bcm2835
make clean
rm -f config.cache
./configure --host=aarch64-none-elf \
CC="/c/arm-gnu-toolchain/bin/aarch64-none-elf-gcc --specs=nosys.specs" \
AR=/c/arm-gnu-toolchain/bin/aarch64-none-elf-ar \
RANLIB=/c/arm-gnu-toolchain/bin/aarch64-none-elf-ranlib \
CFLAGS="-I/c/Users/divye/freertos_demo/FreeRTOS-Kernel/include -I/c/Users/divye/freertos_demo -I/c/Users/divye/freertos_demo/Fr
make
Verify libbcm2835.a :
ls /c/Users/divye/bcm2835/src/libbcm2835.a
Build and Flash Project :
cd /c/Users/divye/freertos_demo/build
rm -rf *
cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=/c/arm-gnu-toolchain/bin/aarch64-none-elf-gcc \
-DCMAKE_CXX_COMPILER=/c/arm-gnu-toolchain/bin/aarch64-none-elf-g++ \
-CMAKE_ASM_COMPILER=/c/arm-gnu-toolchain/bin/aarch64-none-elf-as
make
/c/arm-gnu-toolchain/bin/aarch64-none-elf-objcopy -O binary freertos_demo.elf freertos_demo.bin
openocd -f interface/ftdi.cfg -f target/bcm2710.cfg -c "program freertos_demo.bin 0x80000000 verify reset exit"
Test Output : Monitor UART (GPIO 14/15, 115200 baud) via PuTTY for task outputs (e.g., G0 , P0 ).
4.3. Remaining Challenges
Microsecond Delays: bcm2835_delayMicroseconds approximation may need refinement for precision.
Interrupt Handling: Ensure configUNIQUE_INTERRUPT_PRIORITIES aligns with BCM2710A1’s GIC.
Testing: Runtime behavior (e.g., sine wave/5G tasks) untested due to compilation issues.
5. Summary
The FreeRTOS implementation on the Raspberry Pi Zero 2 W involved:
Downloading FreeRTOS and libbcm2835 via Git.
Setting up the toolchain, CMake, and VS Code.
Configuring FreeRTOSConfig.h and patching bcm2835.c for bare-metal compatibility.
Resolving multiple errors related to missing headers, configuration defines, and Linux dependencies.
Challenges included toolchain setup, IntelliSense issues, and libbcm2835 incompatibilities, addressed through path updates and code patches.
The project is close to compilation, pending a successful libbcm2835 build. Future steps include testing and optimizing for specific tasks (e.g., GPIO-based sine
wave generation).
6. Recommendations
Verify bcm2835.c patches manually to ensure no residual Linux dependencies.
Test with a minimal FreeRTOS task (e.g., LED blink) before integrating complex features.
Document runtime errors via UART for debugging.