{"record":{"id":"ecc6c8742f381e23","repo":"embassy-rs/embassy","slug":"usb-clock-should-be-one-of-16-19-2-20-24-26-3","errorCode":null,"errorMessage":"USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.","messagePattern":"USB clock should be one of 16, 19\\.2, 20, 24, 26, 32Mhz 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":20,"sourceCode":"\n#[cfg_attr(usb, path = \"usb.rs\")]\n#[cfg_attr(otg, path = \"otg.rs\")]\nmod _version;\npub use _version::*;\n\nuse crate::interrupt::typelevel::Interrupt;\nuse crate::rcc;\n\n/// clock, power initialization stuff that's common for USB and OTG.\nfn common_init<T: Instance>() {\n    // Check the USB clock is enabled and running at exactly 48 MHz.\n    // frequency() will panic if not enabled\n    let freq = T::frequency();\n\n    // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally\n    #[cfg(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs), all(stm32wba, peri_usb_otg_hs)))]\n    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.\",","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/usb/mod.rs#L2-L38","documentation":"On H7RS, U5 (OTG_HS), and WBA (OTG_HS) parts the USBPHYC embeds a PLL that must be fed one of a fixed set of reference frequencies (16, 19.2, 20, 24, 26, or 32 MHz) to internally generate 48/60 MHz for OTG_FS/HS. embassy-stm32 checks the configured peripheral clock at common_init and panics if it is outside that set, because the PHY PLL cannot lock to any other input.","triggerScenarios":"Initializing any embassy USB driver on stm32h7rs, stm32u5 with OTG_HS, or stm32wba with OTG_HS while RCC::frequency() for the USB peripheral returns a value not in {16, 19.2, 20, 24, 26, 32} MHz.","commonSituations":"Default or copied RCC clock trees that yield e.g. 48 MHz or 40 MHz to the USB peripheral; changing sysclk/PLL settings for performance and silently changing the USB kernel clock; porting code from F4/H7 (which need 48 MHz) to U5/H7RS/WBA (which need a PHY-PLL-legal frequency).","solutions":["Adjust the RCC configuration so the USB peripheral clock is exactly one of 16, 19.2, 20, 24, 26, or 32 MHz (typically via a dedicated PLL or the CRS/PLL3 output)","Print/inspect rcc.usb().frequency() (or the kernel clock mux settings) before initializing USB to confirm the value","Use embassy-stm32's clock configuration examples for your exact chip as the starting point","On U5/WBA, if you only need FS, use the OTG_FS instance instead, which does not go through this HS-PHY PLL check"],"exampleFix":"// before: PLL3 configured so usb clock = 48_000_000 (valid on F4, invalid on H7RS/U5/WBA HS)\nconfig.pll3 = Some(Pll { divq: ..., /* -> 48 MHz */ .. });\n// after\nconfig.pll3 = Some(Pll { divq: ..., /* -> 32_000_000 */ .. });\n// then verify: assert!([16,19.2,20,24,26,32].contains(&(freq/1_000_000)))","handlingStrategy":"validation","validationCode":"let freq = <periph>::frequency();\nassert!([16_000_000u32, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0), \"USB clk {} Hz not PHY-PLL legal\", freq.0);","typeGuard":"fn usb_clk_phy_legal(hz: u32) -> bool { [16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&hz) }","tryCatchPattern":null,"preventionTips":["Validate rcc.usb().frequency() immediately after setting the clock tree, before USB init","Derive the USB clock from a dedicated PLL with known output, not shared generic prescalers","Start from the embassy-stm32 example clock config for your exact chip family","Re-check whenever sysclk/PLL dividers change"],"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"}