embassy-rs/embassy · error
PLL is unavailable in voltage range 4
Error message
PLL is unavailable in voltage range 4
What it means
Per RM0456 §11.4.10, the STM32U5 PLL cannot run when the core voltage scaling is Range 4 (lowest power, lowest max frequency). embassy-stm32's init_pll enforces this and panics if a PLL is requested while voltage_range is VoltageScale::Range4.
Solutions
- Change config.voltage_range to Range1, Range2, or Range3 (checking VCO 128–544/330 MHz and output limits for the range)
- Or remove/disable all PLL configurations to run legitimately in Range4
- Verify VCO and PLL output frequencies against the selected range's limits (vco 128–544 MHz R1/R2, 128–330 MHz R3; out max 208/110/55 MHz)
Example fix
// before
config.voltage_range = VoltageScale::Range4;
config.pll1 = Some(PllConfig { source: PllSource::Hsi, ... }); // panic
// after
config.voltage_range = VoltageScale::Range1; // or Range2/Range3 as power budget allows
config.pll1 = Some(PllConfig { source: PllSource::Hsi, ... }); Defensive patterns
Strategy: validation
Validate before calling
if config.pll1.is_some() || config.pll2.is_some() || config.pll3.is_some() {
assert!(config.voltage_range != VoltageScale::Range4, "PLL unavailable in Range 4");
}
// also check VCO/output limits per range:
// Range1/2: VCO 128-544 MHz, out <=208/110 MHz; Range3: VCO 128-330 MHz, out <=55 MHz Type guard
fn pll_ok_in_range(range: VoltageScale, has_pll: bool) -> bool {
!has_pll || !matches!(range, VoltageScale::Range4)
} Prevention
- Never combine VoltageScale::Range4 with any PLL config
- Consult RM0456 §11.4.10 limits when choosing voltage range
- For low power with PLL needed, use Range3 instead of Range4
- Validate VCO and PLL output against range-specific maxima
When it happens
Trigger: rcc init with config.voltage_range = VoltageScale::Range4 and any PLL1/PLL2/PLL3 configured (PLL source Some).
Common situations: Choosing Range4 for low-power operation while still needing a PLL-derived clock (e.g. for USB or a high sysclk); copying a config that sets Range4 but leaves PLLs enabled.
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 select PLL source as DISABLE
- 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/9b6d0e9cb7d88c54.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/rcc/u5.rs:633
let src_freq = match pll.source {
PllSource::Disable => panic!("must not select PLL source as DISABLE"),
PllSource::Hse => unwrap!(input.hse),
PllSource::Hsi => unwrap!(input.hsi),
PllSource::Msis => unwrap!(input.msi),
};
// Calculate the reference clock, which is the source divided by m
let ref_freq = src_freq / pll.prediv;
// Check limits per RM0456 § 11.4.6
assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16));
// Check PLL clocks per RM0456 § 11.4.10
let (vco_min, vco_max, out_max) = match voltage_range {
VoltageScale::Range1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)),
VoltageScale::Range2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)),
VoltageScale::Range3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)),
VoltageScale::Range4 => panic!("PLL is unavailable in voltage range 4"),
};
// Calculate the PLL VCO clock
let vco_freq = ref_freq * pll.mul;
assert!(vco_freq >= vco_min && vco_freq <= vco_max);
// Calculate output clocks.
let p = pll.divp.map(|div| vco_freq / div);
let q = pll.divq.map(|div| vco_freq / div);
let r = pll.divr.map(|div| vco_freq / div);
for freq in [p, q, r] {
if let Some(freq) = freq {
assert!(freq <= out_max);
}
}
let divr = match instance {
PllInstance::Pll1 => RCC.pll1divr(),View on GitHub (pinned to 463a07b963)