embassy-rs/embassy · error

Selected PCLK2 frequency is too high for ADC with largest…

Error message

Selected PCLK2 frequency is too high for ADC with largest possible prescaler.

What it means

The F1-style ADC (v2) derives its prescaler from PCLK2 using only Div2/4/6/8. The helper `from_pclk2` computes the required division; if even the maximum divide-by-8 leaves the ADC clock over MAX_FREQUENCY, there is no valid ADCCPRE value and the code panics at construction time.

Solutions

  1. Lower PCLK2 in the RCC config (set APB2 prescaler so PCLK2/8 <= MAX_FREQUENCY, e.g. <=14 MHz)
  2. Reduce SYSCLK/HSE-driven PLL output
  3. Verify PCLK2 frequency with embassy rcc trace output and recalculate the required prescaler

Example fix

// before
config.rcc.apb2_pre = APB2Prescaler::Div1; // PCLK2 = 72MHz, ADC too fast
// after
config.rcc.apb2_pre = APB2Prescaler::Div2; // PCLK2 = 36MHz -> ADC = 4.5..9MHz OK
Defensive patterns

Strategy: validation

Validate before calling

let pclk2_hz = pclk2_frequency();
let max_adc_hz = MAX_FREQUENCY.0; // e.g. 14 MHz on F1
assert!(pclk2_hz / 8 <= max_adc_hz, "PCLK2 {} too high for ADC", pclk2_hz);

Prevention

When it happens

Trigger: Calling `Adc::new_with_config(...)` (which calls from_pclk2) on an F1 target where PCLK2/8 > MAX_FREQUENCY — i.e., PCLK2 above roughly 8x the ADC clock limit (e.g. PCLK2 > 56 MHz if ADC max is 14 MHz).

Common situations: Overclocked or aggressively tuned RCC setups (PCLK2 at 64/72 MHz without ADC-aware clocking); copying a 72 MHz HSE config where APB2 is not divided; older codebases built before ADC clock checks existed.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/adc/v2.rs:98

    pub fn start_time_us() -> u32 {
        10
    }
}

fn from_pclk2(freq: Hertz) -> Adcpre {
    // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
    #[cfg(stm32f2)]
    const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
    // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
    #[cfg(not(stm32f2))]
    const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
    let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0);
    match raw_div {
        0..=1 => Adcpre::Div2,
        2..=3 => Adcpre::Div4,
        4..=5 => Adcpre::Div6,
        6..=7 => Adcpre::Div8,
        _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
    }
}

/// ADC configuration
#[derive(Default)]
pub struct AdcConfig {
    pub resolution: Option<Resolution>,
}

impl AdcRegs for crate::pac::adc::Adc {
    fn data(&self) -> *mut u16 {
        crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
    }

    fn enable(&self) {
        self.cr2().modify(|reg| {
            reg.set_adon(true);
        });

View on GitHub (pinned to 463a07b963)