embassy-rs/embassy · error
must not select PLL source as DISABLE
Error message
must not select PLL source as DISABLE
What it means
During PLL initialization, embassy-stm32 requires the PLL clock source to be an actual oscillator (HSE, HSI, or MSI). `PllSource::Disable` exists only as a 'no PLL' placeholder, so selecting it as the source of a configured PLL is a configuration contradiction and the library panics via `panic!("must not select PLL source as DISABLE")`.
Solutions
- Set `pll.source` to `PllSource::Hse`, `PllSource::Hsi`, or `PllSource::Msi` in the rcc config.
- If no PLL is wanted, remove the `pll` field entirely (set it to None / omit it) instead of leaving source as Disable.
- If using HSE/HIS/MSI as source, ensure the corresponding oscillator is configured and enabled in the same rcc config (hse: Some(...), hsi: true, or msi config), since the source frequency is `unwrap!`ed.
Example fix
// before
pll: Some(PllConfig {
source: PllSource::Disable,
prediv: PllPreDiv::DIV1,
mul: PllMul::MUL9,
..Default::default()
}),
// after
pll: Some(PllConfig {
source: PllSource::Hse,
prediv: PllPreDiv::DIV1,
mul: PllMul::MUL9,
..Default::default()
}), Defensive patterns
Strategy: validation
Validate before calling
if let Some(pll) = &config.rcc.pll {
assert!(pll.source != PllSource::Disable, "rcc.pll.source must be Hse/Hsi/Msi, not Disable");
} Type guard
fn pll_source_valid(pll: &PllConfig) -> bool {
!matches!(pll.source, PllSource::Disable)
} Prevention
- Never leave PllConfig.source at its default when the pll field is Some.
- Prefer omitting the pll field entirely over a placeholder Disable config.
- Keep PLL source and oscillator config in the same board-config struct so they cannot diverge.
When it happens
Trigger: Calling `init()` / `Config::default()` with an `rcc.pll` Some(PllConfig) whose `source` field is `PllSource::Disable`, i.e. configuring PLL dividers/mul but leaving the source at its default `Disable` value.
Common situations: Copying a PLL config snippet but forgetting to set `.source` to Hse/Hsi/Msi; constructing PllConfig programmatically with Default derive; refactoring board configs and dropping the source assignment.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- IC source was set to PLL , but it is not currently enabled
- LSE frequency more than 5% off from 32.768 kHz, cannot use…
- MSIx auto-calibration is enabled for a source that has not…
- LSE frequency more than 5% off from 32.768 kHz, cannot use…
- MCLK frequency < 9.5 MHz is not compatible with the TRNG
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/1c3cb3dbc94cbb8c.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/rcc/l.rs:715
pub msi: Option<Hertz>,
}
#[allow(unused)]
#[derive(Default)]
pub(super) struct PllOutput {
pub p: Option<Hertz>,
pub q: Option<Hertz>,
pub r: Option<Hertz>,
}
pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
// Disable PLL
pll_enable(instance, false);
let Some(pll) = config else { return PllOutput::default() };
let pll_src = match pll.source {
PllSource::Disable => panic!("must not select PLL source as DISABLE"),
PllSource::Hse => unwrap!(input.hse),
PllSource::Hsi => unwrap!(input.hsi),
PllSource::Msi => unwrap!(input.msi),
};
let vco_freq = pll_src / pll.prediv * pll.mul;
let p = pll.divp.map(|div| vco_freq / div);
let q = pll.divq.map(|div| vco_freq / div);
let r = pll.divr.map(|div| vco_freq / div);
#[cfg(stm32l5)]
if instance == PllInstance::Pllsai2 {
assert!(q.is_none(), "PLLSAI2_Q is not available on L5");
assert!(r.is_none(), "PLLSAI2_R is not available on L5");
}
macro_rules! write_fields {View on GitHub (pinned to 463a07b963)