embassy-rs/embassy · error

Maximal allowed frequency for ADC4 is

Error message

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

What it means

The ADC4 driver on STM32C0-family parts clocks the ADC from a kernel clock divided by a prescaler. If, even after applying the largest supported prescaler, the resulting ADC4 clock exceeds MAX_ADC_CLK_FREQ, the constructor panics because the ADC would run outside its datasheet limits, where conversions are inaccurate or unreliable. The limit depends on package/voltage, hence the pointer to ST docs.

Solutions

  1. Lower the ADC4 kernel clock in your RCC config (choose a slower clock source, e.g. a divided HCLK or a low-speed oscillator)
  2. Reduce overall system frequency so the derived ADC4 clock fits under MAX_ADC_CLK_FREQ
  3. Check ST's datasheet/reference manual for the exact MHz limit for your specific package and voltage range

Example fix

// before
let config = Config::default(); // ADC4 clock derived from fast HCLK
// after: select a slower ADC4 kernel clock in rcc
config.rcc.adc4_clock_source = Some(Adc4ClockSource::HCLK / 4); // or a slow oscillator
Defensive patterns

Strategy: validation

Validate before calling

// check before constructing ADC4
let adc_freq = adc4_kernel_clock_hz; // from your RCC config
let max_presc = 128u32; // largest supported prescaler
assert!(adc_freq / max_presc <= MAX_ADC_CLK_FREQ_HZ, "ADC4 clock too high: {}", adc_freq);

Prevention

When it happens

Trigger: Calling `Adc4::new_adc4(...)` (or whatever constructs ADC4 in adc4.rs) while the ADC4 kernel clock frequency divided by the best achievable prescaler still exceeds MAX_ADC_CLK_FREQ — i.e., the peripheral clock source feeding ADC4 is configured too fast in RCC.

Common situations: Running the MCU at a high sysclk/PLL frequency and mapping ADC4's kernel clock from a fast bus clock without lowering it; forgetting to configure ADC4's clock source to a slower oscillator (e.g. HCLK vs. sync/ASYNC slow clock); copying RCC init code from a lower-frequency board.

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

Appendix: source

Thrown at embassy-stm32/src/adc/adc4.rs:389

    fn wait_done(&self) -> bool {
        self.isr().read().eos()
    }
}

impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> {
    /// Create a new ADC driver.
    pub fn new_adc4(adc: Peri<'d, T>) -> Self {
        rcc::enable_and_reset::<T>();
        let prescaler = from_ker_ck(T::frequency());

        T::regs().ccr().modify(|w| w.set_presc(prescaler));

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

        if frequency > MAX_ADC_CLK_FREQ {
            panic!(
                "Maximal allowed frequency for ADC4 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().isr().modify(|w| {
            w.set_ldordy(true);
        });
        T::regs().cr().modify(|w| {
            w.set_advregen(true);
        });
        while !T::regs().isr().read().ldordy() {}

        T::regs().isr().modify(|w| {
            w.set_ldordy(true);
        });

        T::regs().cr().modify(|w| w.set_adcal(true));

View on GitHub (pinned to 463a07b963)