nRF54L15 (Nordic ultra-low-power wireless SoC) — application core
The nRF54L15 pairs a 128 MHz Cortex-M33 application core with a RISC-V PPR (peripheral processor) and FLPR (fast lightweight processor), plus a Bluetooth 5.4 radio. This LabWired profile models the application core — the half that runs user firmware.
Two things make this part different from every Nordic device already onboarded, and both are places where a wrong profile fails silently rather than loudly:
- NVM is RRAM, not flash. It is based at
0x0and is 1524 KB — an odd number that is correct, not a typo to be rounded to 1.5 MB. There is no NVMC; there is an RRAM controller at0x5004_B000. - Timekeeping is the GRTC (Global RTC), not RTC0/RTC1. The nRF52 RTC model is deliberately not mapped on this part.
The address map is otherwise conventional for a modern Nordic device: every
peripheral sits behind one devicetree node with
ranges = <0x0 0x5000_0000 0x1000_0000>, so a DT reg = <0xc6000> is absolute
0x500C_6000. 0x5000_0000 is the secure alias and is the devicetree
default (0x4000_0000 is the non-secure alias, selected by
USE_NON_SECURE_ADDRESS_MAP). This profile maps the secure view. FICR, UICR and
the RRAM controller are outside that window at their own absolute addresses.
Status at a glance
| Aspect | Status |
|---|---|
| Chip yaml | configs/chips/nrf54l15.yaml |
| System yaml | configs/systems/nrf54l15dk.yaml |
| Reference firmware | examples/nrf54l15-dk/ (bare-metal C, no SDK) |
| Validation | tests/nrf54l15_boot.rs (7) + firmware_survival::test_nrf54l15_smoke_survival + test_nrf54l15_lights_dk_led0 |
| Tier | sim-validated, bare-metal only — no Zephyr boot yet, no silicon diff |
What is proven
A bare-metal C firmware, built with arm-none-eabi-gcc and no vendor SDK, no
CMSIS and no Zephyr, boots end to end:
- reset vector at RRAM
0x0; initial SP0x2004_0000(256 KB SRAM) .datacopy out of RRAM,.bsszero- GPIO P2: DIRSET/OUTSET drive DK LED0 (P2.09) — asserted at the pin, not just assumed
- UARTE20 EasyDMA TX at 115200 → console sink, banner captured
Deliberately dependency-free: the less code between reset and the first UARTE byte, the more precisely a failure localises to the simulator rather than to a vendor HAL.
What is NOT proven
Stated plainly, because a fidelity table that only lists successes is marketing:
- No silicon diff. Nothing here has been compared against a real nRF54L15
over SWD. Every "✅ behavioural" below means the model satisfies the firmware
we have run, not the model matches silicon. The board is classified
NOT_SHIPPED with
reset_oracle: Nonefor exactly this reason. - The radio RF/PHY is not modelled — no 2.4 GHz link, no BLE link-layer, no 802.15.4. What is modelled is the CPU-time contention a BLE connection event causes: the smart-ring demo schedules a periodic SysTick "connection event" ISR that busy-holds the core for an event window, and because the TWIM advances each sensor's sample clock on real (GRTC) time, a PPG drain that falls behind during the event overflows its FIFO exactly as silicon would. This reproduces the digital/timing class of the "PPG unreliable under BLE load" failure (CPU starvation + poll jitter). It does not model the analog class — radio-TX current spikes coupling into the PPG analog front-end — which a digital simulator cannot represent.
- The PPR and FLPR coprocessors are not modelled; this is the M33 only.
What is proven: unmodified upstream Zephyr v4.4 boots byte-exactly
(test_nrf54l15_zephyr_survival), and the realistic ring BOM (BMI270 IMU with HW
step counter, MAX30102 PPG, TMP117 skin temp, DRV2605 haptic, 1-channel GPIO
touch) enumerates and runs the Part-2 sensor manager end to end.
Peripherals (from chip yaml)
| Peripheral | Base (secure) | Status | Notes |
|---|---|---|---|
| Cortex-M33 | — | ✅ modeled | Application core only; PPR/FLPR not modeled |
| UARTE20 (console) | 0x500C_6000 | ✅ behavioural | EasyDMA TX → console sink (shared nRF UARTE model) |
| UARTE30 | 0x5010_4000 | ✅ behavioural | Same model |
| TIMER10 | 0x5008_5000 | ✅ behavioural | cc-num = 8 (not the nRF52 default of 4) |
| TIMER20/21/22 | 0x500C_A000 … | ✅ behavioural | cc-num = 6 |
| GPIO P0 / P1 / P2 | 0x5010_9B00 / 0x500D_7D00 / 0x5004_FF00 | ✅ modeled | Widths differ: 7 / 17 / 11 pins. See the base-address note below. |
| TEMP | 0x500D_7000 | ✅ behavioural | Die temperature; nRF52-compatible layout |
| EGU10 / EGU20 | 0x5008_7000 / 0x500C_9000 | ✅ behavioural | Shared nRF EGU model |
| GPIOTE20 / GPIOTE30 | 0x500D_A000 / 0x5010_C000 | ✅ behavioural | Shared nRF GPIOTE model |
| GRTC | 0x500E_2000 | ⚠️ see below | Global RTC — the part's primary timekeeper |
| CLOCK / POWER | 0x5010_E000 | ⚪ benign stub | nRF54L oscillator control is not nRF52-compatible, so the nRF52 CLOCK model is deliberately not reused. A bare-metal boot runs from the default HFINT and never touches it. |
| RRAMC | 0x5004_B000 | ⚪ benign stub | Firmware executing from RRAM never needs it |
| Regulators | 0x5012_0000 | ⚪ benign stub | Write-only on the boot path |
| DPPIC20 / DPPIC30 | 0x500C_2000 / 0x5010_2000 | ⚪ benign stub | Event fabric; poked but not polled on a UART boot |
| FICR / UICR | 0x00FF_C000 / 0x00FF_D000 | ⚪ benign stub | Outside the peripheral window; unprovisioned UICR reads 0 |
| RADIO (BLE / 802.15.4) | 0x5008_A000 | ❌ not mapped | RF/PHY not modelled; BLE CPU-time contention is (SysTick event ISR + wall-clock TWIM) |
| SysTick | 0xE000_E010 (SCS) | ✅ modeled | ARMv8-M core timer; raises exception 15. configure_cortex_m omits it, so declared in the profile |
The GPIO base-address trap
Worth its own section, because it cost real debugging time and it is the single most likely mistake when extending this profile.
A Nordic GPIO devicetree node points at the OUT register, which lives at
peripheral_base + 0x500 — not at the peripheral base. The DT gives
gpio2@50400 (absolute 0x5005_0400), so the peripheral base is
0x5004_FF00. The gpio model uses peripheral-relative offsets (OUT 0x504,
OUTSET 0x508, IN 0x510, DIR 0x514, DIRSET 0x518), so this subtraction is
what makes a firmware write to the DT address land on the right register.
Map the DT address directly and every GPIO register sits 0x500 too high. The
UART still works. The board still boots. The banner still prints. A UART-only
survival test still passes. Only the pins never move.
This is exactly why test_nrf54l15_lights_dk_led0 asserts DIR and OUT at
the pin after booting the real ELF, rather than trusting the banner.
The identical bug was found and fixed in configs/chips/nrf5340.yaml during
this onboarding — see commit fix(nrf5340): GPIO peripheral bases were 0x500
too high.
Board I/O (nRF54L15-DK)
From the Zephyr board devicetree
boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi. Note the LEDs are split
across two ports, which is what makes the per-port ngpios values load-bearing.
| Signal | Port.pin | Polarity |
|---|---|---|
| LED0 | P2.09 | active high |
| LED1 | P1.10 | active high |
| LED2 | P2.07 | active high |
| LED3 | P1.14 | active high |
| Button0 | P1.13 | active low, pull-up |
| Button1 | P1.09 | active low, pull-up |
| Button2 | P1.08 | active low, pull-up |
| Button3 | P0.04 | active low, pull-up |
Sources
- Zephyr devicetree
dts/vendor/nordic/nrf54l_05_10_15.dtsiandnrf54l15.dtsi— address map, IRQ numbers,ngpios,cc-num, memory sizes. This is the exact view firmware is linked against, which is the same sourcing rule used fornrf5340.yaml. - Zephyr board devicetree
boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi— LED/button pin map. - nRF54L15 Product Specification — cross-check of the memory map.
Next steps
In the order I would do them:
- Promote the GRTC to a full behavioural model and boot unmodified Zephyr
samples/hello_worldfornrf54l15dk/nrf54l15/cpuapp. That is the step that moves this profile to the same tier as nRF5340. - TWIM/SPIM personalities.
uart20/spi20/twi20are one instance at0x500C_6000in three personalities; only UARTE is mapped. A sensor-carrying system manifest needs TWIM on a different instance (e.g.twi21at0x500C_7000). - Silicon diff over SWD, which is the only thing that turns "✅ behavioural" into a validated claim.
- RADIO, PPR/FLPR — large, and only worth it with a concrete firmware driving them.