embassy-rs/embassy · error

must not set PllSource::Disable

Error message

must not set PllSource::Disable

What it means

init_pll is only called for PLLs the user actually configured, and PllSource::Disable means 'this PLL is off'. Passing Disable inside a Pll config is contradictory — there is no input clock to divide — so init_pll panics immediately. Every configured PLL must give a real source: Hsi, Hse or Csi.

Solutions

  1. Remove the PLL from the Config (set the field to None) if it should be disabled — do not configure it with PllSource::Disable.
  2. Set source to PllSource::Hsi, Hse or Csi (whichever the board provides) in the Pll struct.
  3. Check constructors/builders for a default source of Disable being left in place.

Example fix

// before
let config = Config {
    pll1: Some(Pll { source: PllSource::Disable, prediv: PllPreDiv::Div1, ..Default::default() }),
    ..Default::default()
};
// after
let config = Config {
    pll1: Some(Pll { source: PllSource::Hse, prediv: PllPreDiv::Div1, ..Default::default() }),
    ..Default::default()
};
Defensive patterns

Strategy: validation

Validate before calling

fn configured(pll: &Option<Pll>) -> bool {
    pll.as_ref().map_or(true, |p| p.source != PllSource::Disable)
}
assert!(configured(&config.pll1) && configured(&config.pll2) && configured(&config.pll3));

Prevention

When it happens

Trigger: Constructing a Pll { source: PllSource::Disable, .. } and putting it into config.pll1/pll2/pll3 on H7/H5/WL-family targets, so init -> init_pll receives Disable.

Common situations: Building PLL configs programmatically where a default() starts with Disable and was never replaced; copy-pasting a 'disabled' placeholder struct into the config; generic code that fills Config pll fields unconditionally.

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


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/289f89603867e98b. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/rcc/h.rs:963

    #[allow(dead_code)]
    t: Option<Hertz>,
}

fn disable_pll(num: usize) {
    // Stop PLL
    RCC.cr().modify(|w| w.set_pllon(num, false));
    while RCC.cr().read().pllrdy(num) {}

    // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
    #[cfg(any(stm32h7, stm32h7rs))]
    RCC.pllckselr().write(|w| w.set_divm(num, PllPreDiv::from_bits(0)));
    #[cfg(stm32h5)]
    RCC.pllcfgr(num).write(|w| w.set_divm(PllPreDiv::from_bits(0)));
}

fn init_pll(num: usize, config: Pll, input: &PllInput) -> PllOutput {
    let in_clk = match config.source {
        PllSource::Disable => panic!("must not set PllSource::Disable"),
        PllSource::Hsi => unwrap!(input.hsi),
        PllSource::Hse => unwrap!(input.hse),
        PllSource::Csi => unwrap!(input.csi),
    };

    let ref_clk = in_clk / config.prediv as u32;

    let ref_range = match ref_clk.0 {
        ..=1_999_999 => Pllrge::Range1,
        ..=3_999_999 => Pllrge::Range2,
        ..=7_999_999 => Pllrge::Range4,
        ..=16_000_000 => Pllrge::Range8,
        x => panic!("pll ref_clk out of range: {} hz", x),
    };

    // The smaller range (150 to 420 MHz) must
    // be chosen when the reference clock frequency is lower than 2 MHz.
    let wide_allowed = ref_range != Pllrge::Range1;

View on GitHub (pinned to 463a07b963)