embassy-rs/embassy · error

AHB frequency is too low

Error message

AHB frequency is too low

What it means

The USBHS (high-speed USB) driver computes the USB turn-around time (TRDT) from the AHB bus clock frequency. For high-speed operation the AHB clock must be at least 30 MHz (asserted directly), and for full-speed operation there is a lookup table with a minimum of ~14.2 MHz. A configured clock below these thresholds makes reliable USB timing impossible, so the driver panics.

Solutions

  1. Increase the AHB clock frequency in your clock initialization to ≥ 30 MHz for high-speed USB (≥ 14.2 MHz minimum for full speed).
  2. Reduce the AHB clock divider in the CCM configuration.
  3. If the clock cannot be raised, use a lower USB speed mode that the current frequency supports (per the TRDT lookup table).

Example fix

// before (board clock init)
let mut ccm = CCM::new(...);
ccm.set_ahb_divider(6); // AHB ends up ~12 MHz
// after
ccm.set_ahb_divider(2); // AHB >= 30 MHz, satisfies USBHS TRDT requirement
Defensive patterns

Strategy: validation

Validate before calling

let ahb_freq = clocks.ahb().raw();
assert!(ahb_freq >= 30_000_000, "AHB {} Hz too low for USBHS high speed", ahb_freq);

Type guard

fn usbhs_ok(ahb_hz: u32, high_speed: bool) -> bool {
    if high_speed { ahb_hz >= 30_000_000 } else { ahb_hz >= 14_200_000 }
}

Prevention

When it happens

Trigger: Creating/configuring the USBHS peripheral with `Config` speed set to HIGH_SPEED while the AHB clock is < 30 MHz (hits the assert with the fuller message), or FULL_SPEED_EXTERNAL/FULL_SPEED_INTERNAL with AHB frequency below 14.2 MHz (hits the table's 0..=14_199_999 arm).

Common situations: Clock tree misconfiguration on i.MX RT chips where the AHB divider is too high; running USBHS off a default reset clock; changing board clock init after enabling USB.

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

Appendix: source

Thrown at embassy-nrf/src/usb/usbhs.rs:353

}

fn current_hclk() -> u32 {
    match pac::OSCILLATORS.pll().currentfreq().read().currentfreq() {
        pac::oscillators::vals::Currentfreq::Ck128m => 128_000_000,
        pac::oscillators::vals::Currentfreq::Ck64m => 64_000_000,
        _ => unreachable!(),
    }
}

fn calculate_trdt(speed: Dspd) -> u8 {
    let ahb_freq = current_hclk();
    match speed {
        Dspd::HIGH_SPEED => {
            assert!(ahb_freq >= 30_000_000, "AHB frequency is too low for USBHS");
            0x9
        }
        Dspd::FULL_SPEED_EXTERNAL | Dspd::FULL_SPEED_INTERNAL => match ahb_freq {
            0..=14_199_999 => panic!("AHB frequency is too low"),
            14_200_000..=14_999_999 => 0xF,
            15_000_000..=15_999_999 => 0xE,
            16_000_000..=17_199_999 => 0xD,
            17_200_000..=18_499_999 => 0xC,
            18_500_000..=19_999_999 => 0xB,
            20_000_000..=21_799_999 => 0xA,
            21_800_000..=23_999_999 => 0x9,
            24_000_000..=27_499_999 => 0x8,
            27_500_000..=31_999_999 => 0x7,
            32_000_000..=u32::MAX => 0x6,
        },
        _ => unimplemented!(),
    }
}

fn busy_wait_us(us: u32) {
    #[cfg(feature = "time")]
    embassy_time::block_for(embassy_time::Duration::from_micros(us as u64));

View on GitHub (pinned to 463a07b963)