embassy-rs/embassy · error

reserved PLL source not allowed

Error message

reserved PLL source not allowed

What it means

During PLL frequency computation for STM32N6, embassy-stm32 matches on the selected PLL source (Pllsel). Only HSI, MSI, HSE and I2S_CKIN are valid; any other Pllsel discriminant (a reserved value, reached via from_bits on raw register/config bits) hits the wildcard arm and panics. It guards against computing frequencies from an undefined clock source.

Solutions

  1. Set the PLL source to Pllsel::Hsi, Pllsel::Msi, Pllsel::Hse or Pllsel::I2sCkin explicitly
  2. Ensure the input.hsi/msi/hse/i2s_ckin Option is populated in the RccInput for the chosen source (unwrap! would otherwise panic too)
  3. Avoid constructing Pllsel from raw bits; use the enum variants

Example fix

// before
let pll = Pll::DivP { source: unsafe { Pllsel::from_bits(0x7) }, divm, divn, divp1, divp2 };
// after
let pll = Pll::DivP { source: Pllsel::Hse, divm, divn, divp1, divp2 };
Defensive patterns

Strategy: validation

Validate before calling

fn pll_source_is_real(s: Pllsel) -> bool {
    matches!(s, Pllsel::Hsi | Pllsel::Msi | Pllsel::Hse | Pllsel::I2sCkin)
}
assert!(pll_source_is_real(my_pll.source));

Type guard

fn as_valid_pll_source(bits: u8) -> Option<Pllsel> {
    Pllsel::from_bits(bits).filter(|s| !matches!(s, Pllsel::_RESERVED_5 | Pllsel::_RESERVED_6 | Pllsel::_RESERVED_7))
}

Prevention

When it happens

Trigger: pll_output called with Pll::DivP (non-bypass) config whose `source` field holds a reserved Pllsel value — i.e. a Pllsel constructed from raw bits not corresponding to Hsi/Msi/Hse/I2sCkin.

Common situations: Casting arbitrary integers into Pllsel via from_bits/transmute; a config generated from device-tree or HAL registers containing a reserved encoding; corrupt or vendor-tool-generated clock configs.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/rcc/n6.rs:747

    cfgr1.modify(|w| w.set_pllbyp(false));
}

fn pll_output(pll_config: Option<Pll>, input: &PllInput) -> PllOutput {
    match pll_config {
        Some(Pll::Oscillator {
            source,
            divm,
            fractional: _,
            divn,
            divp1,
            divp2,
        }) => {
            let in_clk = match source {
                Pllsel::Hsi => unwrap!(input.hsi),
                Pllsel::Msi => unwrap!(input.msi),
                Pllsel::Hse => unwrap!(input.hse),
                Pllsel::I2sCkin => unwrap!(input.i2s_ckin),
                _ => panic!("reserved PLL source not allowed"),
            };
            let m = divm.to_bits() as u32;
            let n = divn as u32;
            let p1 = divp1.to_bits() as u32;
            let p2 = divp2.to_bits() as u32;

            PllOutput {
                divm: Some(Hertz(m)),
                divn: Some(Hertz(n)),
                divp1: Some(Hertz(p1)),
                divp2: Some(Hertz(p2)),
                output: Some(Hertz(in_clk.0 / m * n / p1 / p2)),
            }
        }
        Some(Pll::Bypass { source }) => {
            let in_clk = match source {
                Pllsel::Hsi => unwrap!(input.hsi),
                Pllsel::Msi => unwrap!(input.msi),

View on GitHub (pinned to 463a07b963)