embassy-rs/embassy · error
Source must be equal across all enabled PLLs.
Error message
Source must be equal across all enabled PLLs.
What it means
On H7/H7RS the PLLSRC mux is a single shared register field feeding PLL1, PLL2 and PLL3, so all enabled PLLs must select the same source (HSE, HSI, or CSI). init checks this with all_equal and panics if two enabled PLLs disagree. Disabled PLLs (None) are ignored by the check.
Solutions
- Set the same PllSource on pll1, pll2 and pll3 (the ones that are Some) in the Config.
- Use prediv (DIVM) per-PLL to derive the reference frequencies you need from the single shared source.
- Verify with the clock tree that the shared source frequency supports all three PLL outputs.
Example fix
// before
let config = Config {
pll1: Some(Pll { source: PllSource::HSE, ..Default::default() }),
pll3: Some(Pll { source: PllSource::CSI, ..Default::default() }),
..Default::default()
};
// after
let config = Config {
pll1: Some(Pll { source: PllSource::HSE, ..Default::default() }),
pll3: Some(Pll { source: PllSource::HSE, ..Default::default() }),
..Default::default()
}; Defensive patterns
Strategy: validation
Validate before calling
let sources: Vec<_> = [config.pll1.as_ref(), config.pll2.as_ref(), config.pll3.as_ref()]
.into_iter().flatten().map(|p| p.source).collect();
assert!(sources.windows(2).all(|w| w[0] == w[1]), "H7: all enabled PLLs must share one PLLSRC"); Prevention
- Treat PLLSRC as a board-level decision on H7; define it once and reuse in every PLL struct.
- Use per-PLL DIVM/prediv for frequency shaping instead of different sources.
- Re-check the clock tree after enabling additional PLLs (SAI, USB, SDMMC).
When it happens
Trigger: Passing a Config in which, e.g., pll1 uses PllSource::HSE and pll2 or pll3 uses PllSource::HSI (or CSI) on stm32h7/stm32h7rs; any combination of two or more Some(pll) entries with differing .source values.
Common situations: Individually copying per-PLL configs from datasheets without noticing they share one source mux; migrating configs from L4/F4 (independent sources) to H7; enabling a second PLL for SAI/USB with a 'more convenient' different source.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- if PLL source is HSI, PLL prediv must be 2.
- if PLL source is PLL2, Config::pll2 must also be set.
- must not set PllSource::Disable
- pll ref_clk out of range
- pll vco_clk out of range
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/a5290dcc170b2540.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/rcc/h.rs:538
// Configure HSI48.
let hsi48 = config.hsi48.map(super::init_hsi48);
// Configure CSI.
RCC.cr().modify(|w| w.set_csion(config.csi));
let csi = match config.csi {
false => None,
true => {
while !RCC.cr().read().csirdy() {}
Some(CSI_FREQ)
}
};
// H7 has shared PLLSRC, check it's equal in all PLLs.
#[cfg(any(stm32h7, stm32h7rs))]
{
let plls = [&config.pll1, &config.pll2, &config.pll3];
if !super::util::all_equal(plls.into_iter().flatten().map(|p| p.source)) {
panic!("Source must be equal across all enabled PLLs.")
};
}
// Configure PLLs.
let pll_input = PllInput { csi, hse, hsi };
disable_pll(0);
let pll1 = config
.pll1
.map_or_else(PllOutput::default, |c| init_pll(0, c, &pll_input));
disable_pll(1);
let pll2 = config
.pll2
.map_or_else(PllOutput::default, |c| init_pll(1, c, &pll_input));
#[cfg(any(rcc_h5, stm32h7, stm32h7rs))]
disable_pll(2);
#[cfg(any(rcc_h5, stm32h7, stm32h7rs))]
let pll3 = config
.pll3View on GitHub (pinned to 463a07b963)