nRF54L15 PDM clock runs at ~1/32 of expected (PCLK1M instead of PCLK32M) on a custom board - works on DK
Summary
On a custom nRF54L15 board, the PDM peripheral clock (PDM_CLK) comes out at 20 kHz measured on a logic analyzer, where I expect 1.28 MHz (fs = 16 kHz, RATIO = 80). The PDM PRESCALER register reads 25 (correct), so the divider is right - but the clock source feeding the PDM is ~32x too low: it behaves as if the PDM is sourced from PCLK1M (~1 MHz) instead of PCLK32M (32 MHz).
The same application/driver path works on the nRF54L15-DK. Critically, the stock "known-good" firmware that works on the DK shows the identical ~1/32 clock on this custom board, so this is not specific to my application code.
I'm looking for: what determines whether the PDM gets PCLK32M vs a much lower peripheral clock, and how do I force the 32 MHz peripheral clock (PCLK32M) to the PERI domain / the PDM on a custom board?
Environment
- nRF Connect SDK v3.3.0 (Zephyr 4.3.99)
- SoC: nRF54L15 (cpuapp), custom board
- Zephyr DMIC API →
dmic_nrfx_pdmdriver, nodespdm20andpdm21 - Mics: Infineon IM72D128V PDM. pdm20 = P1.12 (CLK) / P1.09 (DIN); pdm21 = P1.11 (CLK) / P1.10 (DIN)
- Requested config:
pcm_rate = 16000, 16-bit,min/max_pdm_clk_freqbracket = 1.17–1.70 MHz
Measurements / evidence
| Measurement | Method | Result |
|---|---|---|
| PDM_CLK pin frequency | logic analyzer on P1.12 | 20.0 kHz (expected 1.28 MHz) |
| PDM PRESCALER register | nrf_pdm_prescaler_get(NRF_PDM20) at runtime |
25 (correct for 1.28 MHz from 32 MHz) |
| Implied PDM source clock | 20 kHz × PRESCALER (×2 per datasheet formula) | ~0.5–1.0 MHz (≈ PCLK1M; ~1/32 of PCLK32M) |
| CPU clock | timed a fixed CPU loop against GRTC/k_uptime | ~64 MHz (full speed) |
| HFXO start | z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF) + onoff_request, spin-wait |
starts OK in ~5 ms |
dmic_configure() |
return value | 0 (success), blocks flow, no -EINVAL |
| PCM data | drained blocks | constant (mic not clocked in its operating range - consistent with a clock far below the IM72D128V's ~1 MHz minimum) |
So: divider correct, CPU full speed, HFXO healthy - only the PDM's peripheral source clock is ~1/32 of PCLK32M. The nRF54L15 PDM has only a PRESCALER register (no CLKSELECT/MCLKCONFIG), i.e. it is hardwired to PCLK32M, so there is no DT clock-source to reroute.
What I have already tried (no change to the ~1/32 ratio)
DeviceTree / Kconfig (all matched to the nRF54L15-DK board files):
clock-source = "PCLK32M"and"PCLK32M_HFXO"(the latter raised it from ~6 kHz to ~20 kHz, but no further)&clock { status = "okay"; }→CONFIG_CLOCK_CONTROL_NRF=y&hfxo { load-capacitors = "internal"; load-capacitance-femtofarad = <…>; }&lfxo { load-capacitors = "internal"; … }®ulators { status = "okay"; }+&vregmain { regulator-initial-mode = <NRF5X_REG_MODE_DCDC>; }+CONFIG_REGULATOR=y&grtcidentical to DK (owned-channels, status okay)CONFIG_PM_DEVICE=y,CONFIG_PM_DEVICE_RUNTIME=y- PDM clock bracket variations (1.17–1.70 MHz → PRESCALER 25; 380–640 kHz → PRESCALER 63). The output scales exactly with PRESCALER, confirming the divider works and the source is fixed at ~1/32.
Application:
- Held constant-latency:
nrf_sys_event_request_global_constlat()(CONFIG_NRF_SYS_EVENT=y) for the lifetime of capture. - Verified
CONFIG_CLOCK_CONTROL_NRF=y,CONFIG_REGULATOR=y, DCDC mode, PRESCALER value, HFXO start, CPU speed all in the flashed image.
The key data point
The proto firmware that runs correctly on the nRF54L15-DK (real PDM audio) produces the same ~1/32 PDM clock on this custom board. Same SoC, same SDK, equivalent DT - only the physical board differs.
Questions
- On the nRF54L15, what establishes PCLK32M (32 MHz) for a PERI-domain peripheral like the PDM, and under what condition would a PERI peripheral instead be clocked at ~PCLK1M (~1 MHz) - a clean ~1/32?
- Is there a board-level dependency (supply/decoupling, DCDC inductor, a specific clock or power-domain request) required for PCLK32M to reach the PERI domain that the DK satisfies but a custom board might not?
- The PDM
PRESCALERreads 25 and the pin is 20 kHz - can you confirm theCLK = PCLK32M / (2 × PRESCALER)vsCLK = PCLK32M / PRESCALERformula for the nRF54L15, so I can back-compute the true source frequency exactly? - Is there a register I can read at runtime to confirm the actual PCLK32M frequency / the PDM's clock source, to prove whether it is PCLK1M vs PCLK32M?
Minimal DT (PDM + clock/power), matched to the DK
&clock { status = "okay"; };
®ulators { status = "okay"; };
&vregmain { status = "okay"; regulator-initial-mode = <NRF5X_REG_MODE_DCDC>; };
&hfxo { load-capacitors = "internal"; load-capacitance-femtofarad = <8000>; };
&lfxo { load-capacitors = "internal"; load-capacitance-femtofarad = <17000>; };
&pdm20 {
status = "okay";
pinctrl-0 = <&pdm20_default_alt>; /* CLK P1.12, DIN P1.09 */
pinctrl-names = "default";
clock-source = "PCLK32M";
queue-size = <20>;
};
prj.conf (clock/power relevant):
CONFIG_AUDIO=y
CONFIG_AUDIO_DMIC=y
CONFIG_AUDIO_DMIC_NRFX_PDM=y
CONFIG_CLOCK_CONTROL_NRF=y
CONFIG_REGULATOR=y
CONFIG_NRF_SYS_EVENT=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y