t4as

Research note · 2026-10-01

nRF54L15 PAwR Root Cause: the 32 kHz Clock

Date: 2026-10-01 (overnight bench session plus follow-up the same day)

This note closes the May investigation. Run IDs refer to the round-two log directory logs/r2/2026-10-01_nrf54_tag/ and, for the re-analysis, the May logs/correlated_pawr/ runs.

Result

The Makerdiary nRF54L15 Connect Kit’s 32.768 kHz crystal (LFXO), with the board file’s internal capacitor setting of 15.5 pF, runs +174.17 ppm fast relative to the board’s 32 MHz crystal. Firmware declares the default 50 ppm (CONFIG_CLOCK_CONTROL_NRF_K32SRC_50PPM). PAwR and periodic-sync receive windows are sized from the declared accuracy of both ends, so the receiver gets the first event after sync, found with a wide window, and misses every later one: recv_cb(buf == NULL), then sync loss. A second Connect Kit unit, the May AP, measures +167 to +182 ppm from the air. Declaring a conservative accuracy (CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y) or using the RC oscillator fixes it.

Revised later on 1 October after a review: frequencies are stated relative to the reference actually used, the LFRC reading is no longer used as evidence about the reference, the 18 pF point is measured instead of extrapolated, and the capacitor value is described as CINT, not CL.

Bench

Role Board Firmware
AP / gateway nRF5340 Audio DK ESL gateway (Thingy:91 X nRF5340 configuration, host link via the DK’s USB)
Device under test nRF54L15 Connect Kit (round-two unit) per run
Control Pro Micro nRF52840 same probe source as the DUT, later the ESL tag

PAwR profile: interval 1408 × 1.25 ms = 1.76 s, one subevent, 2M PHY.

Runs, one variable each

Run Change nRF54L15 result
R2 production ESL tag service, chip-erased 1 good event, then RX_FAILED on every event (1 of 22)
E5 AP holds the connection 15 s after PAST fails at the second event with the link still up: the disconnect is not the trigger
E4c passive probe, no connection, no PAST exactly 1 good subevent per sync: 15 syncs, 15 good, 60 NULL in 12 min
E7 same probe source on the nRF52840, same AP, same time 137 of 137
T1 nRF54L15 low-frequency clock from the RC oscillator 157 of 157
T1b crystal kept, accuracy declared 500 ppm 181 of 182
T1c crystal load 17.0 pF instead of 15.5, 50 ppm 179 of 183, 1 sync loss in 6 min (marginal)

A void run is worth recording too. A 1M-PHY variant (E6) looked like it broke onboarding, but the gateway’s persistent tag registry hadn’t been cleared after the tag was erased, so the drops were a procedure error. That run doesn’t count.

Kconfig trap found on the way. The SoftDevice Controller only includes PAwR receive support (CONFIG_BT_CTLR_SDC_PAWR_SYNC) when both PAST sender and receiver are enabled, even with CONFIG_BT_PER_ADV_SYNC_RSP=y. Otherwise Kconfig prints a warning, the sync is plain periodic (num_subevents=0), and bt_le_per_adv_sync_subevent() returns -EIO.

The clock, measured on the chip

A small meter: the kernel clock (GRTC, kept by the LF clock through sleep) timed against a TIMER on the 16 MHz clock with the 32 MHz crystal running, 30-second windows, CPU asleep.

Setting Error Spread over 10 windows
LFXO 4.0 pF +775.21 ppm ±0.03 ppm
LFXO 10.0 pF +357.27 ppm ±0.01 ppm
LFXO 15.5 pF (board file) +174.17 ppm ±0.03 ppm
LFXO 17.0 pF +148.70 ppm ±0.03 ppm
LFXO 18.0 pF (maximum) +126.03 ppm ±0.02 ppm
LFRC (sanity check only, see below) about −6 ppm ±50 ppm (calibration steps)

All values are relative to the board’s 32 MHz crystal (HFXO), which hasn’t been calibrated; the board maker doesn’t publish its part or tolerance. The reading follows the load setting while the HFXO stays the same, so the measured interval is paced by the 32 kHz crystal. Even the 18 pF maximum leaves +126 ppm, so tuning can’t bring this crystal to 50 ppm.

The LFRC row only checks the measurement path. The LFRC is calibrated against the HFXO, so it reads near zero relative to the HFXO by construction and says nothing about the HFXO itself.

The devicetree value is the SoC’s internal capacitor setting (CINT), not the crystal’s rated load (CL). Nordic derives CINT from CL plus PCB and pin stray capacitance; 15.5 pF suits a crystal of roughly 9 pF CL. That even 18 pF stays at +126 ppm suggests the fitted crystal needs more load than the internal capacitors provide. The part number isn’t known, so this is not verified.

Host-side timing (device uptime against serial arrival times) could not measure this: the debugger’s USB-UART bridge adds up to 0.5 s of latency jitter.

The May AP, re-timed from the May captures

Periodic advertising has no random delay, so its packets sit on an exact grid. The raccoon sniffer stamps each packet with a 1 MHz timer on its own crystal. Rebuilding the grid index from the gaps and fitting time against it gives the transmitter’s period in that radio’s time.

May run Sniffer radio Packets Span AP clock
115809Z 0 126 7.5 s +167.0 ppm
131239Z 0 177 10.1 s +170.2 ppm
145757Z 1 118 8.4 s +182.4 ppm
150808Z 0 169 10.1 s +167.2 ppm
162544Z 2 93 7.3 s +178.8 ppm
163537Z 2 243 19.6 s +176.6 ppm
165004Z 1 195 18.7 s +174.9 ppm
172925Z (direct AA) 0 292 22.9 s +169.4 ppm
172925Z 0 213 18.3 s +170.3 ppm
181151Z (direct AA) 0 150 8.3 s +179.8 ppm
181151Z 1 233 19.4 s +176.1 ppm
184712Z 1 248 20.2 s +174.9 ppm

Excluded: 160433Z (56 packets, 250 µs rms residual) and 155517Z (10 packets in 0.2 s). Residuals are 28–145 µs rms against 1.2–4 ms of accumulated drift per run. The values are relative to each sniffer radio’s own crystal, which isn’t calibrated either; three independent radios agreeing within about ±8 ppm make a shared 170 ppm error on their side very unlikely. PAwR event timing is scheduled from the AP’s 32 kHz clock, so this measures that clock, not the AP’s 32 MHz crystal.

Why the pairing matters

Every board on the bench, each relative to its own 32 MHz crystal (uncalibrated, so comparisons between boards carry both crystals’ unknown errors): Audio DK +39.1 ppm, Pro Micro nRF52840 +59.6 ppm, Connect Kit +174.2 ppm. A receiver must absorb the relative drift:

AP → receiver Relative drift Result
DK → Pro Micro ≈ 21 ppm works
DK → nRF54L15 on RC ≈ 40 ppm works
DK → nRF54L15 at 17 pF ≈ 110 ppm marginal
nRF54L15 → Pro Micro ≈ 114 ppm works (17 of 18 answered)
DK → nRF54L15 at 15.5 pF ≈ 135 ppm fails
nRF54L15 at 10 pF (+357) → Pro Micro, AP declares 50 ppm ≈ 297 ppm never syncs, 0 of 10
same, AP declares 500 ppm ≈ 297 ppm 10 of 10

With 50 + 50 ppm declared the break falls between about 110 and 135 ppm. The last two rows show the AP’s declared accuracy reaching the tag (through SyncInfo/PAST) and protecting it.

A drift that is constant from event to event, against a fixed window margin, gives a step rather than a gradual decline. That fits the abrupt 302/303 interval edge from May. It has not been fitted quantitatively, and the May tag’s own clock was not measured. May’s subevent 0/1 split and the five-subevent rescue at interval 1408 are not explained by this note.

The fix in the product

esl_tag_node (the production ESL tag service on the nRF54L15) with one added line, CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y:

  • 18 of 18 status requests answered in 2.01–3.51 s (the nRF52840 tag on the same gateway: 17 of 18).
  • Soak, 10.3 h: one sync throughout, 21,006 events received, 97 failed (0.46 %), 9 missed, 0 sync losses, 246 sensor reads served.

The access-point configuration for the Connect Kit carries the same line. Choosing between 500 ppm, 250 ppm and the RC oscillator is a power question, measured next.