FreeRTOS on the ARM Automotive Kit (NXP S32Z2)
Status note
This page records hardware bring-up design notes for the freertos-s32z2
target. It is intentionally lower-level than the user guide and may reference
NXP-generated/private files or bench scripts that are not present in the public
repository. For the supported build entry point and current user workflow, see
FreeRTOS S32Z2.
This document records the design of Phase 5 of the FreeRTOS port: bringing the
actuation firmware to the ARM Automotive Kit (X-S32Z27X-DC, NXP S32Z2,
Cortex-R52). Issue: autowarefoundation/autoware-safety-island#1.
Scope
The kit runs FreeRTOS with feature parity to the existing Zephyr backend on the same SoC:
Cortex-R52 RTU0, lock-step mode (reset default).
FreeRTOS V11.1.0 via NXP’s Real-Time Drivers (RTD) Cortex-R52 port.
lwIP socket layer, BSD-socket-compatible, driving the NETC Ethernet controller.
CycloneDDS cross-compiled statically into the firmware image.
DDS_ONLYcontrol-command output mode; CAN is not validated on the kit in Phase 5.150 ms periodic controller loop, identical to the Zephyr backend.
Out of scope: eSync OTA, Linux-side Autoware integration, CAN frame observation, Phase 6 tuning, an on-hardware CI job, migration to the Phase 2 stack (issue #14).
Build tree layout
The Phase 5 build is an additional CMake entry point under
actuation_module/freertos_s32z2/ that does not modify the existing
actuation_module/freertos/ POSIX-simulator build, the Zephyr boards under
actuation_module/boards/, or the PAL backend headers under
actuation_module/include/platform/freertos/*.h. The intended hardware path
may add S32Z2-specific variant headers under
actuation_module/include/platform/freertos/s32z2/ when carrying the lwIP
bring-up forward.
The intended hardware networking path uses an S32Z2-specific FreeRTOS network
backend. In the public tree, platform_network.h still dispatches FreeRTOS
targets through platform/freertos/freertos_network.h; update this dispatcher
and the matching backend when carrying the S32Z2 lwIP bring-up path forward.
Boot bring-up (B-1)
board_init() calls Mcu_Init / Platform_Init / Port_Init from
the RTD, brings UART9 up at 115200 8N1, and registers the PIT as the FreeRTOS
tick source. configCPU_CLOCK_HZ matches the clock programmed by
Mcu_Init. Newlib’s _write is retargeted to UART9 so printf reaches
the FT232RQ serial port exposed as /dev/ttyUSB0 on the carrier’s J11 USB-C
console (the OpenSDA debug probe exposes /dev/ttyACM0 separately).
A heartbeat task prints actuation alive ticks=N every 150 ms. The B-1
acceptance gate is the appearance of at least five such lines within ten
seconds of reset.
PB configuration prerequisite
The NXP RTD MCAL drivers (Mcu, Clock_Ip, Siul2_Port_Ip, Uart,
Pit) expect post-build configuration structures (*_PBcfg.c) that are
generated by S32 Design Studio’s S32 Config Tools from a .mex board
configuration. The driver packages ship those structures as EB Tresos
templates under $S32_RTD_PATH/RTD/<driver>_TS_*/generate_PB/src/; the
templates contain [!...!] markers that must be expanded by S32 Config
Tools. Until the generated files exist, the firmware does not link.
Workflow:
In S32 Design Studio 3.6.x, import or recreate the
lwip_S32Z27X_FreeRTOS_R52example shipped at$LWIP_PATH/examples/S32Z270/lwip_S32Z27X_FreeRTOS_R52/as a starting point.Open the project’s
.mexin the S32 Configuration Tools editor and configure clock ≥ 240 MHz, UART9 at 115200 8N1, PIT channel 0 as the tick, and Ethernet 0 enabled.Use the Update Code action to expand the templates into the project’s
generate/src/*.c,generate/include/*.handboard/directories.Point
S32CT_GENERATED_DIRat that project root; the build consumesgenerate/src,generate/includeandboard. The generated files inherit the NXP Confidential and Proprietary header from the RTD templates, so they are not committed to this public repository: they are bundled as the privates32ct_configsubmodule, or regenerated locally by developers without submodule access (see the README).
Networking and DDS (B-2)
The intended S32Z2 configure_network() path dispatches to an lwIP bring-up
function that calls tcpip_init(), registers the NETC driver via
ethif_ethernetif_init (from the NXP eth_port.c glue, not the generic
upstream ethernetif_init) / netif_add, requests DHCP, and blocks on a
semaphore until a lease arrives. Keep the dispatcher and backend implementation
in sync before treating this as current behavior.
CycloneDDS is cross-compiled as a static library for Cortex-R52 with the
upstream WITH_FREERTOS=ON and WITH_LWIP=ON options enabled (CycloneDDS
ships dedicated sync/freertos.h and sockets/posix.h + lwIP backends —
no patches required). Security, SSL, shared memory, IPv6, source-specific
multicast, and network partitions are all disabled (see
actuation_module/freertos_s32z2/scripts/build-cdds-target.sh). The host
idlc built by build.sh --platform freertos-s32z2 is reused for IDL → C
generation of autoware_msgs.
The cross-build needs two non-obvious workarounds:
-D__int64_t_defined=1— Ubuntu 24.04’slibnewlib-arm-none-eabi4.4.0 has a header-name mismatch inmachine/_default_types.h(defines___int64_t_definedwith three leading underscores) sointtypes.hnever exposesPRId64/PRIu64. Pre-defining the symbol works around the packaging bug.-include inttypes.hplus-DUSING_RTD=1 -DS32Z27— the NXP-supplied lwIParch/cc.hhas a#ifdef USING_RTDbranch that pulls in the RTD-friendlyDevassert.hpath instead of the toolchain-dependentdevice_registers.hpath.
The Edge ECU peer is the development host itself: dds_pub and dds_sub
(unchanged) compile with host gcc against the host CycloneDDS and run as
edge_ecu_pub / edge_ecu_sub. The acceptance gates are:
Controller Node StartedandActuation Safety Island is Liveappear on UART9.edge_ecu_subreceivesSTEERING REPORTat least twice.actuation_maindoes not return during the verification window.
These are the same string markers used by the POSIX-simulator smoke (PRs #10 / #13).
Flash workflow
The kit is flashed via the NXP s32dbg debugger through west debug
(the nxp_s32dbg runner does not implement the flash command). The
driver scripts live in an out-of-tree MRM_repo/ working directory on the
dev host (the copy used for the production demo rig). MRM_repo/run_before.sh
STEP 4 starts an Xvfb on DISPLAY=:99 before STEP 5 invokes
west_debug.sh — s32dbg is a GUI tool that aborts at SoC connect
with CCS: connection to server refused when no X display is
available, even in batch mode. From inside a Zephyr workspace whose
runners.yaml selects nxp_s32dbg (the s32z270dc2_rtu0_r52@D
board config does):
export DISPLAY=:99
pgrep -x Xvfb >/dev/null || \\
nohup Xvfb :99 -screen 0 1024x768x24 > /tmp/xvfb.log 2>&1 &
source ~/zephyr-env/bin/activate
west debug \\
--s32ds-path=/usr/local/NXP/S32DS.3.6.2 \\
-d build/actuation_module \\
--tool-opt='--batch'
The --tool-opt='--batch' flag makes the GDB session non-interactive so
the firmware is loaded, the entry breakpoint is released, and control
returns to the shell after the kit starts running. A successful run loads
roughly 1.2 MB in 6 s and shortly afterwards /dev/ttyUSB0 prints
Starting Controller Node..., Controller Node Started and
Actuation Safety Island is Live.
When the SoC connection still fails after Xvfb is up, clean up residual
debugger state per the demo’s retry recipe
(pkill -9 -f '(gta|s32dbg|arm-none-eabi-gdb)',
rm -rf /tmp/*nxp_s32dbg*, free TCP/45000) and retry. If three retries
fail, the SoC is unreachable for physical reasons: power, J6 JTAG seating,
J14 jumper, J17/J18 boot mode, or the front-panel S2 reset.
References
NXP S32Z2 product page: https://www.nxp.com/products/S32Z2
S32Z2 block diagram: https://www.nxp.com/assets/block-diagram/en/S32Z2.pdf
X-S32Z27X-DC Zephyr docs (cross-reference for hardware wiring): https://docs.zephyrproject.org/latest/boards/nxp/s32z2xxdc2/doc/index.html
How to download RTD: https://www.nxp.com/company/about-nxp/smarter-world-videos/HOW-TO-DWLD-RTD