embassy-rs/embassy · error

Invalid HCLK frequency - should be at least 25 MHz.

Error message

Invalid HCLK frequency - should be at least 25 MHz.

What it means

The v1 Ethernet Station Management block derives MDC from HCLK. To keep MDC in the 1–2.5 MHz window, HCLK must be at least 25 MHz so the smallest divider is valid; below that no clock-range value exists and the driver panics.

Solutions

  1. Raise HCLK1 to at least 25 MHz in the RCC config before creating the Ethernet driver.
  2. Verify rcc::get_freqs().hclk1 is nonzero and correct after RCC init.
  3. Use a board RCC default meeting Ethernet clocking requirements.

Example fix

// before
config.sys = Sysclk::HSI; // ~16 MHz
// after
config.sys = Sysclk::PLL1_R; // 80 MHz PLL -> hclk >= 25 MHz
Defensive patterns

Strategy: validation

Validate before calling

let hclk = embassy_stm32::rcc::get_freqs().hclk1.0;
assert!(hclk >= 25_000_000, "Ethernet requires HCLK1 >= 25 MHz, got {}", hclk);

Prevention

When it happens

Trigger: Constructing the v1 StationManagement while rcc hclk1 is < 25 MHz (hclk_mhz in 0..=24).

Common situations: Low-power/HSI-only clock configs; hclk1 unassigned or very small; early bring-up before RCC is fully configured.

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

Appendix: source

Thrown at embassy-stm32/src/eth/sma/v1.rs:46

        critical_section::with(|_| {
            #[cfg(eth_v1a)]
            let reg = crate::pac::RCC.ahbenr();

            #[cfg(any(eth_v1b, eth_v1c))]
            let reg = crate::pac::RCC.ahb1enr();

            reg.modify(|w| {
                w.set_ethen(true);
            })
        });

        let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() };
        let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not.");
        let hclk_mhz = hclk.0 / 1_000_000;

        // Set the MDC clock frequency in the range 1MHz - 2.5MHz
        let clock_range = match hclk_mhz {
            0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
            25..=34 => Cr::Cr2035,     // Divide by 16
            35..=59 => Cr::Cr3560,     // Divide by 26
            60..=99 => Cr::Cr60100,    // Divide by 42
            100..=149 => Cr::Cr100150, // Divide by 62
            150..=216 => Cr::Cr150168, // Divide by 102
            _ => {
                panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
            }
        };

        Self {
            _peri: peri,
            clock_range,
            _pins: [
                new_pin!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh)).unwrap(),
                new_pin!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh)).unwrap(),
            ],
        }

View on GitHub (pinned to 463a07b963)