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
- Add a Some(Pll { ... }) value to config.pll2 when selecting PllSource::PLL2.
- Make sure pll2's config (prediv2, mul) yields a PLL2 frequency that keeps the main PLL within its input limits.
- 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
- On F105/F107, always define pll2 (and prediv2) whenever the main PLL uses PllSource::PLL2.
- Verify the PLL2 output keeps the main PLL input within datasheet limits.
- Keep connectivity-line configs in a board-specific module to avoid reuse on other chips.
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
- if PLL source is HSI, PLL prediv must be 2.
- must not select PLL source as DISABLE
- PLL is unavailable in voltage range 4
- The LCD driver needs the RTC/LCD clock to be running
- Source must be equal across all enabled PLLs.
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)