A quick start guide for deploying RTEMS to xilinx Zedboard
Host
WSL (Windows Subsystem for Linux) running Ubuntu 24.
RTEMS 6.2
Assumes zedboard has factory firmware load from Digilent
Using RSB to Build RTEMS
Dependencies:
- build-essential
- g++
- gdb
- unzip
- pax
- bison
- flex
- texinfo
- python3-dev
- python-is-python3
- libncurses-dev
- zlib1g-dev
- ninja-build
- pkg-config
Toolset
./sb-set-builder --prefix=$PREFIX 6/rtems-arm
Tools can be found in $PREFIX/bin. Consider adding to your PATH
BSP, Kernel, Test Cases
./sb-set-builder --prefix=$PREFIX --target=arm-rtems6 --with-rtems-bsp=arm/xilinx_zynq_zedboard --with-rtems-tests=yes 6/rtems-kernel
Test cases .exe can be found in $PREFIX/arm. I will be using the ticker.exe for the rest of the guide. It will under the var $TELF
U-Boot
repo: GitHub - Xilinx/u-boot-xlnx: The official Xilinx u-boot repository · GitHub
I
used the tag xilinx-v2025.2
Dependencies:
- gcc-arm-linux-gnueabihf
- device-tree-compiler
- libssl-dev
- python3
- python3-dev
- python3-setuptools
- swig
- bison
- flex
- bc
Building
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
make distclean
make xilinx_zynq_virt_defconfig # I think this for qemu, but seems to work
export DEVICE_TREE="zynq-zed"
make -j$(nproc)
You will need u-boot.img and spl/boot.bin
you will also be calling tools/mkimage in the next step. might want to add it to your path
Creating RTEMS Image
using the tools in $PREFIX/bin and u-boot, as well as the desired .exe pointed to by $TELF. I will be using ticker.exe
First confirm the binary start point: arm-rtems6-objdump -d $TELF | less. In this example the magic number is 0x00104000 i.e. the start of the ARM exception table (entry 1 is the reset vector jumps you to address 0x00104040 _start)
Disassembly of section .start:
00104000 <bsp_section_start_begin>:
104000: e59ff018 ldr pc, [pc, #24] @ 104020 <bsp_section_start_begin+0x20>
104004: e59ff018 ldr pc, [pc, #24] @ 104024 <bsp_section_start_begin+0x24>
104008: e59ff018 ldr pc, [pc, #24] @ 104028 <bsp_section_start_begin+0x28>
10400c: e59ff018 ldr pc, [pc, #24] @ 10402c <bsp_section_start_begin+0x2c>
104010: e59ff018 ldr pc, [pc, #24] @ 104030 <bsp_section_start_begin+0x30>
104014: e7f000f0 udf #0
104018: e59ff018 ldr pc, [pc, #24] @ 104038 <bsp_section_start_begin+0x38>
10401c: e59ff018 ldr pc, [pc, #24] @ 10403c <bsp_section_start_begin+0x3c>
104020: 00104040 .word 0x00104040
104024: 00108b18 .word 0x00108b18
104028: 00108b2c .word 0x00108b2c
10402c: 00108b40 .word 0x00108b40
104030: 00108b54 .word 0x00108b54
104034: 00000000 .word 0x00000000
104038: 00108a30 .word 0x00108a30
10403c: 00108b68 .word 0x00108b68
00104040 <_start>:
104040: e3a00000 mov r0, #0
104044: ee070fd5 mcr 15, 0, r0, cr7, cr5, {6}
104048: e59f121c ldr r1, [pc, #540] @ 10426c <bsp_start_hook_0_done+0x44>
10404c: e59f021c ldr r0, [pc, #540] @ 104270 <bsp_start_hook_0_done+0x48>
104050: e0813000 add r3, r1, r0
104054: e10f4000 mrs r4, CPSR
104058: e3a000d1 mov r0, #209 @ 0xd1
10405c: e129f000 msr CPSR_fc, r0
Alternately could use
arm-rtems6-readelf -S $TELF | grep "\.start"
[ 1] .start PROGBITS 00104000 001000 000558 00 AX 0 0 4
Now create the Image
arm-rtems6-objcopy --output-target=binary -S $TELF /tmp/ticker.exe.bin
cat /tmp/ticker.exe.bin | gzip -9 > /tmp/ticker.exe.bin.gz
mkimage -A arm -O rtems -T kernel -a 0x00104000 -e 0x00104000 -n "RTEMS" -d /tmp/ticker.exe.bin.gz /tmp/ticker.exe.img
Image Name: RTEMS
Created: Mon Apr 6 10:15:13 2026
Image Type: ARM RTEMS Kernel Image (gzip compressed)
Data Size: 33981 Bytes = 33.18 KiB = 0.03 MiB
Load Address: 00104000
Entry Point: 00104000
Next compile the script that u-boot will use to boot RTEMS
cat > /tmp/boot.cmd << 'EOF'
fatload mmc 0:1 0x02000000 ticker.exe.img
bootm 0x02000000 - -
EOF
~/work/rtems/projects/zynq_demo/uboot/tools/mkimage \
-A arm -O linux -T script -C none \
-a 0 -e 0 -n "RTEMS Boot" \
-d /tmp/boot.cmd /tmp/boot.scr
In /tmp you will now have ticker.exe.img and boot.scr
SD Card
I used the SD card included with the zedboard. I made a back up and cleaned the files off of it.
It shows up in u-boot as mmc 0:1
But i’m not sure how universal this will be. Some minor adjustments to the boot.scr above might be needed.
WSL Hint
To mount a sd card in wsl first take note of the drive windows assigns the card. In my case D:
# be sure your mount path exist
# mounting
sudo mount -t drvfs D: /mnt/d
# card now accessable under as /mnt/d
# to unmount
sync
sudo umount /mnt/d
# you should then also 'eject' from windows side
Card layout
You will only need 4 files
- boot.bin → the first stage bootloader (or rather what zedboard’s FSBL finds and runs)
- copy in from
u-boot-xlnx/spl/boot.bin
- u-boot.img → the second stage bootloader
- copy in from
u-boot-xlnx/u-boot.img
- boot.scr → u-boot script; built in the last step
- ticker.exe.img → RTEMS image; built in the last step
Minicom
minicom can be used to view the board’s UART output. use the J14 header and 115200 baud rate. your device file may differ
minicom -D /dev/ttyACM0 -b 115200
WSL Hint
usb pass through is a bit difficult in wsl… you will need the usbipd tool and powershell
use usbipd list to find the device. mine came up as USB Serial Device (COM3) with bus id 2-3
first in powershell as admin
usbipd bind --busid=2-3
you should only have to do that once… and the state will show as ‘Shared’
next again in powershell but this time not as admin
usbipd attach --wsl --busid 2-3 --auto-attach
--auto-attach is optional and keeps the process running and re attaches every time the board power cycles
Expected Output
can only attach minicom when the board is on. can use the PS-RST button to get a clean run.
U-Boot 2021.01 (Apr 03 2026 - 16:53:23 -0400)
CPU: Zynq 7z020
Silicon: v3.1
Model: Avnet ZedBoard board
DRAM: ECC disabled 512 MiB
Flash: 0 Bytes
NAND: 0 MiB
MMC: mmc@e0100000: 0
Loading Environment from FAT... *** Warning - bad CRC, using default environment
In: serial@e0001000
Out: serial@e0001000
Err: serial@e0001000
Net:
ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr 0, interface rgmii-id
Warning: ethernet@e000b000 (eth0) using random MAC address - e6:46:02:37:ca:65
eth0: ethernet@e000b000
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
182 bytes read in 17 ms (9.8 KiB/s)
## Executing script at 03000000
34045 bytes read in 22 ms (1.5 MiB/s)
20560 bytes read in 22 ms (912.1 KiB/s)
## Booting kernel from Legacy Image at 02000000 ...
Image Name: RTEMS
Image Type: ARM RTEMS Kernel Image (gzip compressed)
Data Size: 33981 Bytes = 33.2 KiB
Load Address: 00104000
Entry Point: 00104000
Verifying Checksum ... OK
Uncompressing Kernel Image
## Transferring control to RTEMS (at address 00104000) ...
*** BEGIN OF TEST CLOCK TICK ***
*** TEST VERSION: 6.0.0.not-released
*** TEST STATE: EXPECTED_PASS
*** TEST BUILD: RTEMS_POSIX_API
*** TEST TOOLS: 13.3.0 20240521 (RTEMS 6, RSB 3814cb0e7f86cca2be403eac831f9bf571984659-modified, Newlib 1b3dcfd)
TA1 - rtems_clock_get_tod - 09:00:00 12/31/1988
TA2 - rtems_clock_get_tod - 09:00:00 12/31/1988
TA3 - rtems_clock_get_tod - 09:00:00 12/31/1988
TA1 - rtems_clock_get_tod - 09:00:05 12/31/1988
TA2 - rtems_clock_get_tod - 09:00:10 12/31/1988
TA1 - rtems_clock_get_tod - 09:00:10 12/31/1988
TA1 - rtems_clock_get_tod - 09:00:15 12/31/1988
TA3 - rtems_clock_get_tod - 09:00:15 12/31/1988
TA2 - rtems_clock_get_tod - 09:00:20 12/31/1988
TA1 - rtems_clock_get_tod - 09:00:20 12/31/1988
TA1 - rtems_clock_get_tod - 09:00:25 12/31/1988
TA2 - rtems_clock_get_tod - 09:00:30 12/31/1988
TA1 - rtems_clock_get_tod - 09:00:30 12/31/1988
TA3 - rtems_clock_get_tod - 09:00:30 12/31/1988
*** END OF TEST CLOCK TICK ***
[ RTEMS shutdown ]
lastly see above posts on how u-boot can be used to load an image over the network (better for iterative dev) and hopeful following posts on how to update the bsp once the fpga image moves from factory image.