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 C0-series ADC driver applies a prescaler on the ADC common clock (CCR.PRESC) and picks the largest one it supports. If the ADC clock frequency still exceeds MAX_ADC_CLK_FREQ, the constructor panics, because exceeding the ADC clock limit violates ST's electrical specification and corrupts conversion accuracy. The limit varies per package/voltage, so ST's docs are referenced.

Solutions

  1. Set the ADC kernel clock source in RCC config to a slower clock (e.g. PCLK/HSI16 with proper division)
  2. Lower SYSCLK so the derived ADC clock is within the datasheet limit
  3. Verify the exact MAX_ADC_CLK_FREQ for your package in the ST datasheet and adjust clocking accordingly

Example fix

// before
let config = Config::default(); // ADC clock too fast
// after
config.rcc.adc_clock_source = AdcClockSource::SysClkDiv...; // choose a divided source so adc_clk <= MAX_ADC_CLK_FREQ
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: Calling `Adc::new(...)` for an STM32C0 target when T::frequency() (the ADC kernel clock) divided by the maximum prescaler still exceeds MAX_ADC_CLK_FREQ.

Common situations: High system clock (e.g. 48 MHz HSI at max PLL) feeding the ADC with no slow kernel-clock source selected; reusing RCC config from another board; upgrading embassy-stm32 and hitting stricter frequency 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/3e79593f69ad75c6. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/adc/c0.rs:199

        self.isr().read().eoc()
    }
}

impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
    /// Create a new ADC driver.
    pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
        rcc::enable_and_reset::<T>();

        T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::Sysclk));

        let prescaler = from_ker_ck(T::frequency());
        T::common_regs().ccr().modify(|w| w.set_presc(prescaler));

        let frequency = T::frequency() / prescaler;
        debug!("ADC frequency set to {}", frequency);

        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
            );
        }

        T::regs().cr().modify(|reg| {
            reg.set_advregen(true);
        });

        // "The software must wait for the ADC voltage regulator startup time."
        // See datasheet for the value.
        block_for_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1);

        T::regs().cfgr1().modify(|reg| reg.set_res(resolution));

        // We have to make sure AUTOFF is OFF, but keep its value after calibration.
        let autoff_value = T::regs().cfgr1().read().autoff();
        T::regs().cfgr1().modify(|w| w.set_autoff(false));

View on GitHub (pinned to 463a07b963)