{"record":{"id":"fe6a3a269b666842","repo":"embassy-rs/embassy","slug":"pll-is-unavailable-in-voltage-range-2","errorCode":null,"errorMessage":"PLL is unavailable in voltage range 2","messagePattern":"PLL is unavailable in voltage range 2","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/rcc/wba.rs","lineNumber":518,"sourceCode":"    // Only divide by the HSE prescaler when the PLL source is HSE\n    let src_freq = match pll.source {\n        PllSource::Hse => {\n            // read the prescaler bits and divide\n            let hsepre = RCC.cr().read().hsepre();\n            pre_src_freq / hsepre\n        }\n        _ => pre_src_freq,\n    };\n\n    // Calculate the reference clock, which is the source divided by m\n    let ref_freq = src_freq / pll.prediv;\n    // Check limits per RM0515 § 12.4.3\n    assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16));\n\n    // Check PLL clocks per RM0515 § 12.4.5\n    let (vco_min, vco_max, out_max) = match voltage_range {\n        VoltageScale::Range1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(100)),\n        VoltageScale::Range2 => panic!(\"PLL is unavailable in voltage range 2\"),\n    };\n\n    // Calculate the PLL VCO clock\n    // let vco_freq = ref_freq * pll.mul;\n    // Calculate VCO frequency including fractional part: FVCO = Fref_ck × (N + FRAC/2^13)\n    let numerator = (ref_freq.0 as u64) * (((pll.mul as u64) + 1 << 13) + pll.frac.unwrap_or(0) as u64);\n    let vco_hz = (numerator >> 13) as u32;\n    let vco_freq = Hertz(vco_hz);\n    assert!(vco_freq >= vco_min && vco_freq <= vco_max);\n\n    // Calculate output clocks.\n    let p = pll.divp.map(|div| vco_freq / div);\n    let q = pll.divq.map(|div| vco_freq / div);\n    let r = pll.divr.map(|div| vco_freq / div);\n    for freq in [p, q, r] {\n        if let Some(freq) = freq {\n            assert!(freq <= out_max);\n        }","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/rcc/wba.rs#L500-L536","documentation":"While configuring the PLL, init_pll detects that the core voltage range is set to range 2; per the reference manual (RM0515 §12.4.3-12.4.5 limits checked around this code) the PLL may only run in voltage range 1, so its configuration is rejected. The faulting input is the combination of a PLL-based clock config with a VOS/range-2 low-power setting.","triggerScenarios":"Running rcc init with voltage_scale = VoltageScale::Range2 while also requesting a PLL config (Some(pll)).","commonSituations":"Low-power configurations that drop to Range2 for lower voltage while still needing a PLL-derived clock; copying a PLL setup from another board that runs in Range1.","solutions":["Configure the regulator to VoltageScale::Range1 when using the PLL.","Remove the PLL from the clock config and derive sysclk directly from HSI/HSE if Range2 must be kept.","Check that sysclk <= 100 MHz (typical Range1 constraint) so Range1 is valid for your application."],"exampleFix":"// before\nConfig { voltage_scale: VoltageScale::Range2, clocks: Clocks { pll: Some(..), .. } }\n// after\nConfig { voltage_scale: VoltageScale::Range1, clocks: Clocks { pll: Some(..), .. } }","handlingStrategy":"validation","validationCode":"if let Some(_pll) = &config.clocks.pll { assert!(config.voltage_scale == VoltageScale::Range1, \"PLL requires voltage Range1\"); }","typeGuard":"fn pll_allowed(vs: VoltageScale) -> bool { matches!(vs, VoltageScale::Range1) }","tryCatchPattern":null,"preventionTips":["Pair any PLL usage with VoltageScale::Range1.","For low-power Range2 designs, derive clocks without the PLL.","Check RM0515 clock-tree constraints whenever changing voltage scale."],"tags":["rcc","embedded","panic","voltage-range","pll"],"backgroundTag":"invalid-config-value","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}