embassy-rs/embassy · error

USB HS PHY reference clock should be 19.2, 20 or 24 MHz but…

Error message

USB HS PHY reference clock should be 19.2, 20 or 24 MHz but is {} Hz. Please double-check your RCC settings.

What it means

fsel_from_freq maps the USBPHYC reference clock to the Fsel register value; the PHY PLL only accepts 19.2, 20, or 24 MHz as selectable inputs. If common_init reaches this mapping with any other frequency, there is no valid Fsel encoding, so the library panics rather than misconfiguring the PHY.

Solutions

  1. Set the RCC so the USBPHYC reference clock is exactly 19.2, 20, or 24 MHz (usually via PLL3 with appropriate dividers, per the ST reference manual for your part)
  2. Cross-check against the chip-specific clock-tree example in embassy-stm32 examples/ for your board
  3. If you need OTG_HS, do not reuse a 48 MHz FS clock tree; the HS PHY needs one of the three listed reference frequencies

Example fix

// before
config.pll3.divp/divq -> usbphyc_ck = 32_000_000;
// after
config.pll3.divp/divq -> usbphyc_ck = 24_000_000; // maps to Fsel::Mhz24
Defensive patterns

Strategy: validation

Validate before calling

let freq = <periph>::frequency();
assert!(matches!(freq.0, 19_200_000 | 20_000_000 | 24_000_000), "USBPHYC ref {} Hz not 19.2/20/24 MHz", freq.0);

Type guard

fn phy_ref_ok(hz: u32) -> bool { matches!(hz, 19_200_000 | 20_000_000 | 24_000_000) }

Prevention

When it happens

Trigger: On parts whose OTG_HS goes through the internal USBPHYC, calling fsel_from_freq (via USB driver common_init) with a PHY reference clock outside {19.2, 20, 24} MHz.

Common situations: RCC configurations that feed the USBPHYC 16/26/32 MHz (legal for some other check but not for Fsel), or a generic 48 MHz USB clock routed to the PHY; mixing clock-tree examples across chip families.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/ba9b8d6d4ae56c9c. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/usb/otg.rs:507

    ///
    /// Called by `common_init` before the OTG core is enabled and reset. Empty for every
    /// family whose PHY is handled by the core's own clock/power gating.
    fn phy_init() {}
}

/// STM32N6: map the PHY reference clock to `USBPHYC_CR.FSEL`.
///
/// The integrated High-Speed PHY only accepts these three frequencies
/// (RM0486 Rev 4, `USBPHYC_CR.FSEL`, p. 3929).
#[cfg(stm32n6)]
pub(super) fn fsel_from_freq(freq: crate::time::Hertz) -> crate::pac::usbphyc::vals::Fsel {
    use crate::pac::usbphyc::vals::Fsel;

    match freq.0 {
        19_200_000 => Fsel::Mhz192,
        20_000_000 => Fsel::Mhz20,
        24_000_000 => Fsel::Mhz24,
        _ => panic!(
            "USB HS PHY reference clock should be 19.2, 20 or 24 MHz but is {} Hz. Please double-check your RCC settings.",
            freq.0
        ),
    }
}

/// USB instance trait.
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {
    /// Interrupt for this USB instance.
    type Interrupt: interrupt::typelevel::Interrupt;
}

// Internal PHY pins
pin_trait!(DpPin, Instance);
pin_trait!(DmPin, Instance);

// External PHY pins

View on GitHub (pinned to 463a07b963)