{"record":{"id":"3130ee1659e68d6a","repo":"embassy-rs/embassy","slug":"usb-clock-should-be-48mhz-but-is-hz-please-dou","errorCode":null,"errorMessage":"USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.","messagePattern":"USB clock should be 48Mhz but is (.+?) Hz\\. Please double-check your RCC settings\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/usb/mod.rs","lineNumber":37,"sourceCode":"    if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) {\n        panic!(\n            \"USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.\",\n            freq.0\n        )\n    }\n\n    // On the N6 the OTG core always runs off its integrated High-Speed PHY, whose reference\n    // clock must be 19.2, 20 or 24 MHz (RM0486 Rev 4, USBPHYC_CR.FSEL, p. 3929). Panics\n    // naming the offending frequency; the same mapping programs FSEL in `T::phy_init()`.\n    #[cfg(stm32n6)]\n    let _ = fsel_from_freq(freq);\n\n    // Check frequency is within the 0.25% tolerance allowed by the spec.\n    // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user\n    // has tight clock restrictions due to something else (like audio).\n    #[cfg(not(any(stm32h7rs, stm32n6, all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs))))]\n    if freq.0.abs_diff(48_000_000) > 120_000 {\n        panic!(\n            \"USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.\",\n            freq.0\n        )\n    }\n\n    #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))]\n    critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));\n\n    #[cfg(pwr_h5)]\n    critical_section::with(|_| crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)));\n\n    #[cfg(stm32h7)]\n    {\n        // If true, VDD33USB is generated by internal regulator from VDD50USB\n        // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)\n        // TODO: unhardcode\n        let internal_regulator = false;\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/usb/mod.rs#L19-L55","documentation":"On all other STM32 USB parts (not H7RS/N6/U5-HS/WBA-HS), the USB clock must be 48 MHz with at most 0.25% deviation (±120 kHz), because the OTG core derives its timing directly from that clock. embassy-stm32 validates this in common_init and panics when abs_diff(freq, 48_000_000) > 120_000, since an off-spec clock breaks USB enumeration/timing.","triggerScenarios":"Initializing a USB driver on any non-exception part (e.g. F1/F4/L4/G4/H7-FS) while the USB peripheral's kernel clock is not within 47.88–48.12 MHz.","commonSituations":"RCC PLL tuned for 72/168 MHz sysclk where the USB prescaler yields 47 or 48.5 MHz; CRS/HSI48 not enabled on parts lacking a crystal; audio-oriented clock trees that intentionally detune USB; running on a board without an external 48 MHz-capable PLL path.","solutions":["Reconfigure RCC so the USB kernel clock is exactly 48 MHz (PLL Q divider, USBPRE/OTGFSPRE prescaler)","On parts with HSI48, enable HSI48 with CRS sync to produce a USB-legal 48 MHz without a crystal","Verify the actual frequency with rcc.usb().frequency() (or T::frequency()) before constructing the USB driver","Start from the official embassy-stm32 USB example for your board, which has a known-good clock tree"],"exampleFix":"// before\nconfig.pll.q = 5; // -> usb 47.5 MHz, out of 0.25% tolerance\n// after\nconfig.pll.q = 4; // -> usb 48 MHz\n// sanity check before init:\nassert!(rcc.usb().frequency().0.abs_diff(48_000_000) <= 120_000);","handlingStrategy":"validation","validationCode":"let freq = <periph>::frequency();\nassert!(freq.0.abs_diff(48_000_000) <= 120_000, \"USB clk {} Hz outside 48MHz ±0.25%\", freq.0);","typeGuard":"fn usb_clk_48mhz_ok(hz: u32) -> bool { hz.abs_diff(48_000_000) <= 120_000 }","tryCatchPattern":null,"preventionTips":["Enable HSI48+CRS on parts without a suitable PLL path","Keep the USB prescaler/PLL-Q setting untouched when tuning other clocks","Verify frequency at startup before constructing the USB device","Compare against the 0.25% (±120 kHz) tolerance, not exact equality, if using CRS-trimmed sources"],"tags":["embedded","stm32","usb","rcc","clock-config","panic"],"backgroundTag":"invalid-config-value","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}