embassy-rs/embassy · error

if PLL source is HSI, PLL prediv must be 2.

Error message

if PLL source is HSI, PLL prediv must be 2.

What it means

On certain STM32 F0/F1/F3 parts (not rcc_f0v3/f0v4/f3v3 silicon), the RCC hardware hardwires the HSI path into the PLL to a fixed divide-by-2, so the configurable prediv is ignored. embassy-stm32 panics at init if you specify PllSource::HSI with a PllPreDiv other than Div2, since the requested prediv cannot actually be applied.

Solutions

  1. Set pll.prediv to PllPreDiv::Div2 when using PllSource::HSI on these parts.
  2. If you need a different prediv, switch the PLL source to HSE, which honors the configurable prediv.
  3. Adjust the pll.mul value to compensate so the target PLL output frequency is still achieved with /2.

Example fix

// before
let config = Config {
    pll: Some(Pll { source: PllSource::HSI, prediv: PllPreDiv::Div1, mul: Mul::Mul6 }),
    ..Default::default()
};
// after
let config = Config {
    pll: Some(Pll { source: PllSource::HSI, prediv: PllPreDiv::Div2, mul: Mul::Mul12 }),
    ..Default::default()
};
Defensive patterns

Strategy: validation

Validate before calling

if pll.source == PllSource::HSI {
    assert!(pll.prediv == PllPreDiv::Div2, "HSI PLL source requires prediv = Div2 on this chip");
}

Prevention

When it happens

Trigger: Calling embassy_stm32::rcc init with Config containing pll configured as PllSource::HSI and prediv set to Div1, Div3, Div4, etc., on a target where cfg(not(any(rcc_f0v3, rcc_f0v4, rcc_f3v3))) applies.

Common situations: Porting an RCC config from an F0 v3 or F3 v3 board to a different F0/F3 chip that hardwires HSI/2; copying PLL setups between chip families; assuming prediv is a general-purpose knob on HSI source.

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


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

Appendix: source

Thrown at embassy-stm32/src/rcc/f013.rs:254

        }

        // Configure PLL3
        if let Some(pll3) = config.pll3 {
            RCC.cfgr2().modify(|w| w.set_pll3mul(pll3.mul));
            RCC.cr().modify(|w| w.set_pll3on(true));
            while !RCC.cr().read().pll3rdy() {}
        }
    }

    // Enable PLL
    let pll = config.pll.map(|pll| {
        let (src_val, src_freq) = match pll.src {
            #[cfg(any(rcc_f0v3, rcc_f0v4, rcc_f3v3))]
            PllSource::HSI => (Pllsrc::HsiDivPrediv, unwrap!(hsi)),
            #[cfg(not(any(rcc_f0v3, rcc_f0v4, rcc_f3v3)))]
            PllSource::HSI => {
                if pll.prediv != PllPreDiv::Div2 {
                    panic!("if PLL source is HSI, PLL prediv must be 2.");
                }
                (Pllsrc::HsiDiv2, unwrap!(hsi))
            }
            PllSource::HSE => {
                #[cfg(any(stm32f105, stm32f107))]
                RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::Hse));

                (Pllsrc::HseDivPrediv, unwrap!(hse))
            }
            #[cfg(rcc_f0v4)]
            PllSource::HSI48 => (Pllsrc::Hsi48DivPrediv, unwrap!(hsi48)),
            #[cfg(any(stm32f105, stm32f107))]
            PllSource::PLL2 => {
                if config.pll2.is_none() {
                    panic!("if PLL source is PLL2, Config::pll2 must also be set.");
                }
                RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::Pll2));

View on GitHub (pinned to 463a07b963)