Hello World on ZynqMP R5 with Zephyr OS
- Markus
- Embedded linux , Real time
- July 22, 2026
Table of Contents
The ZynqMP SoC has two Cortex-R5F cores sitting alongside the quad-core Cortex-A53 APU. Most people leave them unused. Here’s how to bring them up with Zephyr RTOS and communicate with Linux over RPMsg — the entire workflow from a running Linux system, no JTAG required.
Why R5 + Zephyr
The R5 cores run at 500MHz and are completely independent from the Linux scheduler. No arch timer interference. No PREEMPT_RT wakeup path. When a hardware interrupt fires, the R5 handles it directly — GIC dispatch to your ISR, nothing in between. That’s the architecture you want for sub-100µs determinism.
Zephyr gives you:
- A real RTOS scheduler on top of the bare hardware
- Built-in OpenAMP/RPMsg for communication back to Linux
- A standard
westbuild system you can run on the ZynqMP board itself - No Vitis, no SDK installer, no Windows VM
Prerequisites
Everything runs on the ZynqMP board running Debian trixie. You need:
apt install python3-pip cmake ninja-build gcc-arm-none-eabi
pip install west pyelftools jsonschema PyYAML
The Zephyr SDK (aarch64 native build, runs on the A53):
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.0/\
zephyr-sdk-0.17.0_linux-aarch64.tar.xz
tar xf zephyr-sdk-0.17.0_linux-aarch64.tar.xz -C /opt/
cd /opt/zephyr-sdk-0.17.0 && ./setup.sh
Kernel requirements
Your Linux kernel needs remoteproc and RPMsg support. Check:
zcat /proc/config.gz | grep -E "REMOTEPROC|XLNX_R5|RPMSG"
You want:
CONFIG_REMOTEPROC=y
CONFIG_XLNX_R5_REMOTEPROC=y
CONFIG_RPMSG=y
CONFIG_RPMSG_CHAR=y
CONFIG_RPMSG_VIRTIO=y
The device tree also needs the R5 subsystem node — the key section in system-user.dtsi:
#include <dt-bindings/power/xlnx-zynqmp-power.h>
/ {
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
rproc_0_fw_image: rproc_0_fw@4000000 {
no-map;
reg = <0x0 0x04000000 0x0 0x00100000>;
};
rpu0vdev0buffer: rpu0vdev0buffer@4100000 {
no-map;
reg = <0x0 0x04100000 0x0 0x100000>;
};
rpu0vdev0vring0: rpu0vdev0vring0@4200000 {
no-map;
reg = <0x0 0x04200000 0x0 0x80000>;
};
rpu0vdev0vring1: rpu0vdev0vring1@4280000 {
no-map;
reg = <0x0 0x04280000 0x0 0x80000>;
};
};
};
&amba {
remoteproc@ffe00000 {
compatible = "xlnx,zynqmp-r5fss";
xlnx,cluster-mode = <0>;
xlnx,tcm-mode = <0>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x00000 0x0 0xffe00000 0x0 0x10000>,
<0x0 0x20000 0x0 0xffe20000 0x0 0x10000>,
<0x1 0x00000 0x0 0xffe90000 0x0 0x10000>,
<0x1 0x20000 0x0 0xffeb0000 0x0 0x10000>;
r5f@0 {
compatible = "xlnx,zynqmp-r5f";
reg = <0x0 0x00000 0x0 0x10000>,
<0x0 0x20000 0x0 0x10000>;
reg-names = "atcm0", "btcm0";
power-domains = <&zynqmp_firmware PD_RPU_0>,
<&zynqmp_firmware PD_R5_0_ATCM>,
<&zynqmp_firmware PD_R5_0_BTCM>;
memory-region = <&rproc_0_fw_image>, <&rpu0vdev0buffer>,
<&rpu0vdev0vring0>, <&rpu0vdev0vring1>;
mboxes = <&ipi_mailbox_rpu0 0>, <&ipi_mailbox_rpu0 1>;
mbox-names = "tx", "rx";
};
};
};
When it works, dmesg confirms:
remoteproc remoteproc0: ffe00000.r5f is available
The Zephyr app
Initialize the workspace (run once):
mkdir ~/zephyr-workspace && cd ~/zephyr-workspace
west init && west update
source zephyr/zephyr-env.sh
The Hello World for R5 is the openamp_rsc_table sample — it boots Zephyr on the R5 and sets up an RPMsg shell back to Linux:
cd zephyr
west build -b zynqmp_rpu \
samples/subsys/ipc/openamp_rsc_table
Build time on the A53: about 45 seconds.
Deploy
cp build/zephyr/zephyr.elf /lib/firmware/hello_r5.elf
# Stop any previous run
echo stop > /sys/class/remoteproc/remoteproc0/state 2>/dev/null; sleep 1
# Load and start
echo hello_r5.elf > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
# Check
cat /sys/class/remoteproc/remoteproc0/state
# running
dmesg shows the full boot sequence:
remoteproc remoteproc0: powering up ffe00000.r5f
remoteproc remoteproc0: Booting fw image hello_r5.elf, size ...
virtio_rpmsg_bus virtio0: rpmsg host is online
remoteproc remoteproc0: remote processor ffe00000.r5f is now up
Talk to it
The RPMsg shell appears as a tty device:
ls /dev/ttyRPMSG*
# /dev/ttyRPMSG0
cat /dev/ttyRPMSG0
# *** Booting Zephyr OS build v4.4.99 ***
# Zephyr Shell on R5
Or interactively:
screen /dev/ttyRPMSG0
You’re now talking to a Zephyr shell running on the R5F at 500MHz, completely independent of Linux scheduling.
Stop the R5
echo stop > /sys/class/remoteproc/remoteproc0/state
Linux gets full hardware ownership back immediately.
What’s next
A “hello world” on R5 is just the beginning. The R5 can:
- Handle hardware interrupts from PL (FPGA) peripherals with sub-10µs latency — impossible to guarantee from Linux userspace
- Run a TTP/fieldbus controller handler deterministically while Linux handles networking, logging, and OTA updates
- Provide a hard real-time floor under an otherwise standard Linux system
The full source will be provided soon!
Tested on Trenz TE0821 (ZU3EG) with Linux 6.12 PREEMPT_RT, Zephyr 4.4.99, Zephyr SDK 1.0.0-beta1.