embassy-rs/embassy · error

Maximal allowed frequency for the ADC is

Error message

Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.

What it means

The v4 ADC driver (C0/G4/H7-class per stm32u5/h7 etc.) checks the ADC kernel clock against MAX_ADC_CLK_FREQ after construction and panics if it exceeds the limit, since datasheet limits guarantee conversion accuracy. On STM32C5 the RCC layer already performs this check, so the check is cfg'd out there. The limit varies by package/voltage per ST docs.

Solutions

  1. Select a slower ADC kernel clock source (e.g. divided HCLK, HSI16, or per-family ADC prescaler) in the RCC config
  2. Lower the source frequency feeding the ADC (reduce PLL/SYSCLK)
  3. Consult the ST datasheet for the exact limit for your package/voltage and recompute the prescaler

Example fix

// before
config.rcc.adc_clock_source = AdcClockSource::AHB; // too fast
// after
config.rcc.adc_clock_source = AdcClockSource::HSI16; // or AHB with prescaler, <= MAX_ADC_CLK_FREQ
Defensive patterns

Strategy: validation

Validate before calling

let adc_clk_hz = adc_kernel_clock_hz();
assert!(adc_clk_hz <= MAX_ADC_CLK_FREQ_HZ, "ADC kernel clock {} Hz exceeds limit", adc_clk_hz);

Prevention

When it happens

Trigger: Calling `Adc::new(...)` when T::frequency() (the ADC kernel clock from RCC) is greater than MAX_ADC_CLK_FREQ, on any supported chip except STM32C5.

Common situations: Mapping the ADC kernel clock from a fast AHB/PLL output without prescaling; overclocked RCC configs; reusing clock init from a different board; bumping embassy-stm32 and encountering stricter runtime checks.

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/3120441505a61d95. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/adc/v4.rs:338

    /// Create a new ADC driver.
    pub fn new(adc: Peri<'d, T>) -> Self {
        rcc::enable_and_reset::<T>();

        #[cfg(not(any(stm32u3, stm32n6, stm32c5)))]
        let prescaler = from_ker_ck(T::frequency());
        #[cfg(not(any(stm32u3, stm32n6, stm32c5)))]
        T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
        #[cfg(not(any(stm32u3, stm32n6, stm32c5)))]
        let frequency = T::frequency() / prescaler;

        #[cfg(any(stm32u3, stm32n6, stm32c5))]
        let frequency = T::frequency();

        info!("ADC frequency set to {}", frequency);

        #[cfg(not(stm32c5))] // C5 checks this in its rcc
        if frequency > MAX_ADC_CLK_FREQ {
            panic!(
                "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
                MAX_ADC_CLK_FREQ.0 / 1_000_000
            );
        }

        #[cfg(stm32h7)]
        {
            let boost = if frequency < Hertz::khz(6_250) {
                Boost::Lt625
            } else if frequency < Hertz::khz(12_500) {
                Boost::Lt125
            } else if frequency < Hertz::mhz(25) {
                Boost::Lt25
            } else {
                Boost::Lt50
            };
            T::regs().cr().modify(|w| w.set_boost(boost));
        }

View on GitHub (pinned to 463a07b963)