embassy-rs/embassy · critical
Failed to configure PLL_SYS
Error message
Failed to configure PLL_SYS: {:?} What it means
During clock initialization, the RP clock setup calls `configure_pll(PLL_SYS, ...)` and panics with the underlying PLL error if the system PLL cannot be locked or configured. The error value (`e`) indicates which PLL setup step failed (e.g. no valid feedback divider, frequency out of range).
Solutions
- Verify `config.hz` matches your board's actual crystal frequency (RP2040 dev boards: 12 MHz)
- Choose a `sys_pll` target frequency within the valid VCO range for your reference clock, or pass `None` to run without the PLL
- Check the returned debug value `{:?}` to see the specific PLLSetupError variant (e.g. VCO out of range)
- Extend/adjust the PLL divider search: pick a refdiv so ref_freq stays in 5–800 MHz and fbdiv/post_div yield a valid VCO
Example fix
// before
let clocks = Clocks::init(&config_with(hz: 12_000_000, sys_pll: Some(125_000_000))); // board crystal is 25 MHz
// after
let clocks = Clocks::init(&Config { hz: 25_000_000, sys_pll: Some(125_000_000), ..config }); // hz matches real crystal
Defensive patterns
Strategy: validation
Validate before calling
fn validate_pll_plan(ref_hz: u32, target_hz: u32) -> Result<(), &'static str> {
// RP2040: VCO must be in 750..=1600 MHz, refdiv so 5..=800 MHz reference
let vco = (ref_hz as u64 * target_hz as u64) ; // compute per configure_pll rules
// perform the same feasibility math configure_pll does and reject early
Ok(())
}
Prevention
- Confirm config.hz matches the board crystal before clock init
- Use default PLL configs unless you have computed dividers yourself
- Keep target frequencies within documented VCO ranges
- Test clock init on the actual hardware revision early
When it happens
Trigger: Calling `Clocks::init` (or `init_with_config`) with a `sys_pll` configuration whose reference frequency, feedback/post divider combination cannot produce a valid VCO output from the crystal frequency (`config.hz`).
Common situations: Using a non-12 MHz crystal (e.g. 12.288 MHz or 25 MHz) with a default PLL config tuned for 12 MHz; requesting a sys frequency outside the VCO range (750 MHz–1.6 GHz VCO constraint); typo in target frequency.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Failed to configure PLL_USB
- timer must be stopped before setting counter
- DMA: error on DMA_0 channel
- InterruptExecutor::start() called multiple times on the…
- InterruptExecutor::spawner() called on uninitialized…
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/a527e866a85b8ac0.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-rp/src/clocks.rs:1110
});
#[cfg(feature = "_rp235x")]
vreg.bod().write(|w| {
w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password
w.set_vsel(voltage.recommended_bod());
w.set_en(true); // Enable brownout detection
});
}
}
let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc {
Some(config) => {
// start XOSC
start_xosc(config.hz, config.delay_multiplier);
let pll_sys_freq = match config.sys_pll {
Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
Ok(freq) => freq,
Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e),
},
None => 0,
};
let pll_usb_freq = match config.usb_pll {
Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
Ok(freq) => freq,
Err(e) => panic!("Failed to configure PLL_USB: {:?}", e),
},
None => 0,
};
(config.hz, pll_sys_freq, pll_usb_freq)
}
None => (0, 0, 0),
};
CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed);View on GitHub (pinned to 463a07b963)