embassy-rs/embassy · error

if PLL source is PLL2, Config::pll2 must also be set.

Error message

if PLL source is PLL2, Config::pll2 must also be set.

What it means

On STM32F105/F107 (connectivity line), the PLL can be clocked from PLL2. Since the driver reads config.pll2 to compute frequencies and configure the shared registers, using PllSource::PLL2 for the main PLL without also supplying config.pll2 makes the configuration incomplete, so init panics with this message.

Solutions

  1. Add a Some(Pll { ... }) value to config.pll2 when selecting PllSource::PLL2.
  2. Make sure pll2's config (prediv2, mul) yields a PLL2 frequency that keeps the main PLL within its input limits.
  3. Alternatively, clock the main PLL from HSE or HSI if PLL2 is not actually needed.

Example fix

// before
let config = Config {
    pll: Some(Pll { source: PllSource::PLL2, prediv: PllPreDiv::Div1, mul: Mul::Mul9 }),
    ..Default::default()
};
// after
let config = Config {
    pll: Some(Pll { source: PllSource::PLL2, prediv: PllPreDiv::Div1, mul: Mul::Mul9 }),
    pll2: Some(Pll { source: PllSource::HSE, prediv: PllPreDiv::Div1, mul: Mul2::Mul8 }),
    prediv2: PllPreDiv::Div1,
    ..Default::default()
};
Defensive patterns

Strategy: validation

Validate before calling

if config.pll.as_ref().map(|p| p.source) == Some(PllSource::PLL2) {
    assert!(config.pll2.is_some(), "PLL2 source requires config.pll2 to be set");
}

Prevention

When it happens

Trigger: Calling rcc init on stm32f105/stm32f107 with config.pll set to PllSource::PLL2 while config.pll2 is None. The panic fires before unwrap!(config.pll2) would even be attempted.

Common situations: Using the PLL2-prediv1 feature of the connectivity line but forgetting the pll2 field; porting configs from non-connectivity-line chips where PLL2 does not exist; misreading Config defaults that leave pll2 None.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

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

            #[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));

                let pll2 = unwrap!(config.pll2);
                let in_freq = hse.unwrap() / config.prediv2;
                let pll2freq = in_freq * pll2.mul;

                (Pllsrc::HseDivPrediv, pll2freq)
            }
        };
        let in_freq = src_freq / pll.prediv;

        rcc_assert!(max::PLL_IN.contains(&in_freq));
        let out_freq = in_freq * pll.mul;
        rcc_assert!(max::PLL_OUT.contains(&out_freq));

        #[cfg(not(stm32f1))]
        RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv));

View on GitHub (pinned to 463a07b963)