Port and integrate FreeRTOS on the Arm Zena CSS Safety Island
Introduction
Build the Cortex-R82 FreeRTOS demo
Build and validate FreeRTOS on the Cortex-R82AE FVP
Load FreeRTOS directly into Zena CSS Safety Island Cluster 1
Add FreeRTOS to the Zena CSS software stack boot flow
Integrate FreeRTOS into Zena CSS with Yocto
Next Steps
Port and integrate FreeRTOS on the Arm Zena CSS Safety Island
Run the existing FreeRTOS demo on the Cortex-R82 AEM FVP
Porting an operating system to a new platform involves changes to startup code, memory maps, interrupts, timers, and peripherals. Before making those changes, reproduce a known-good example on its supported platform. This separates tool installation problems from problems introduced during the port.
You’ll build the existing FreeRTOS symmetric multiprocessing (SMP) and Memory Protection Unit (MPU) demo for Cortex-R82. You’ll then run it on FVP_BaseR_AEMv8R and confirm that the compiler, CMake, FreeRTOS sources, and Fixed Virtual Platform (FVP) work together.
Before you begin
Ensure that you’ve installed the following tools and added their executable directories to your PATH:
- CMake 3.22.1
- Arm GNU Toolchain 15.3 or Arm Compiler for Embedded 6.24
FVP_BaseR_AEMv8Rfrom Fast Models 11.32
You need only one of Arm GNU Toolchain or Arm Compiler for Embedded.
Verify your setup with the following commands, omitting the command for the compiler that you’re not using:
cmake --version
FVP_BaseR_AEMv8R --version
aarch64-none-elf-gcc --version # GNU build
armclang --version # Arm Compiler build
Clone the FreeRTOS sources
Clone the FreeRTOS distribution with its submodules:
git clone --recurse-submodules \
https://github.com/FreeRTOS/FreeRTOS.git \
freertos-r82-baseline
cd freertos-r82-baseline
The Cortex-R82 demo is supplied by the partner-supported demos submodule. The portable kernel code is supplied by the kernel submodule.
Review the Cortex-R82 kernel port
The recursive clone initializes the official FreeRTOS Kernel under FreeRTOS/Source. The demo selects the portable layer in FreeRTOS/Source/portable/GCC/ARM_CR82 through the GCC_ARM_CR82 CMake port name.
Confirm that the Cortex-R82 port files are present:
ls FreeRTOS/Source/portable/GCC/ARM_CR82
The directory contains port.c, portASM.S, portmacro.h, and the MPU wrapper implementation. Together, these files provide the Cortex-R82-specific scheduler, context-switching, interrupt, and MPU support.
Understand the existing demo
You’ll start with a demo that runs FreeRTOS in SMP mode on up to four Cortex-R82 cores. This demo implements a ping/pong-style exchange with three tasks:
- An unprivileged sender places counter values in a shared queue.
- An unprivileged receiver reads the values from the queue.
- A privileged logger prints messages received from both tasks.
The sender and receiver are created with xTaskCreateRestricted(). Their MPU configuration grants access only to their stacks and a small shared region containing the queue handles. Kernel data remains accessible only to privileged code.
Unlike the application that you’ll use later, the demo doesn’t provide an interactive ping command. It starts exchanging messages automatically after FreeRTOS starts.
Understand the baseline limitations
This initial demo is a useful starting point, but its startup and core-identification code depend on behavior provided by FVP_BaseR_AEMv8R configured for aarch64. This behavior doesn’t strictly follow the Cortex-R82 and Cortex-R82AE specifications.
The demo supports entry at Exception Level 1 (EL1) only. Its
fvp_config.txtfile setscluster0.has_pl2=0, so the AEM FVP starts the demo without EL2. The boot code readsCurrentELand enters an error loop unless the value indicates EL1. A platform that starts the cores at EL2 therefore cannot use this startup path unchanged.The demo assumes that the core number is stored in the
Aff0field ofMPIDR_EL1. The AEM FVP uses this layout by default throughcluster0.mpidr_layout=0. The startup code consequently extracts bits[7:0]to select the primary core, allocate a per-core stack, and index the secondary-core state.
The Cortex-R82 affinity layout is different:
MPIDR_EL1 field | AEM demo assumption | Cortex-R82 definition |
|---|---|---|
Aff0, bits [7:0] | Core number | 0, because each core has one thread |
Aff1, bits [15:8] | Not used as the core number | Core number from 0 to 7 |
For the affinity-field definitions, see the Cortex-R82 MPIDR_EL1 register description .
If the original MPIDR_EL1 & 0xFF calculation is used with this layout, every core appears to be core 0. Multiple cores can then perform primary-core initialization, select the same stack, and use incorrect scheduler or interrupt-routing indexes. The Cortex-R82AE port must derive its logical core index from Aff1 and preserve the complete affinity value when targeting a core with a software-generated interrupt.
- The demo doesn’t use the PL011 UART interface. Instead, it sets
semihosting-enable=1to print output to the console through semihosting.
Build the example
Enter the demo directory and build the example with either GCC or Arm Compiler for Embedded. Each compiler uses a separate build directory, which prevents CMake from reusing settings from the other toolchain.
cd FreeRTOS/Demo/ThirdParty/Partner-Supported-Demos/CORTEX_R82_SMP_MPU_FVP_GCC_ARMCLANG
cmake -S . -B build_AEMR \
-DCMAKE_TOOLCHAIN_FILE=gnu_toolchain.cmake
cmake --build build_AEMR --parallel
The generated executable is in build_AEMR for GCC or build_AEMR_armclang for Arm Compiler for Embedded.
Launch the demo on the AEM FVP
The upstream run.sh script expects its default output-directory name. You’ll use different build-directory names so that you can launch the executable directly:
FVP_BaseR_AEMv8R \
--application build_AEMR/cortex_r82_smp_mpu_fvp_example.axf \
--config fvp_config.txt
The FVP starts the application and displays sender and receiver activity in the semihosting console. The core numbers depend on how the SMP scheduler assigns the tasks.
The output is similar to:
[Core: x] Sender: Sent message 0
[Core: y] Receiver: Received message 0
[Core: x] Sender: Sent message 1
[Core: z] Receiver: Received message 1
... (continues) ...
Confirm that the message number received by the receiver matches the number sent by the sender.
Continued output demonstrates that the following components are working together:
- Scheduler
- Timer interrupt
- Interprocessor coordination
- Queues
- MPU-protected shared region
What you’ve accomplished and what’s next
You’ve reproduced the existing Cortex-R82 FreeRTOS example without modifying its platform code. This confirms that your selected compiler, CMake, FreeRTOS source tree, Cortex-R82 portable layer, and AEM FVP are working.
Keep this build as a known-good reference. Next, you’ll adapt the example for FVP_BaseR_Cortex-R82AE, where you’ll address Cortex-R82AE startup behavior. You’ll also address platform-specific memory, timer, interrupt, and UART configuration independently of the toolchain setup.