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
- 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)
- Cross-check against the chip-specific clock-tree example in embassy-stm32 examples/ for your board
- 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
- Configure PLL3 (or the PHY ref mux) to one of 19.2/20/24 MHz for OTG_HS
- Do not reuse a 48 MHz FS clock tree for the HS PHY
- Check the ST reference manual's USBPHYC fsel table when choosing dividers
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
- USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but…
- USB clock should be 48Mhz but is
- AHB frequency is too low
- AHB frequency is too low
- LSE frequency more than 5% off from 32.768 kHz, cannot use…
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 pinsView on GitHub (pinned to 463a07b963)