embassy-rs/embassy · critical

Failed to configure PLL_USB

Error message

Failed to configure PLL_USB: {:?}

What it means

Same failure path as PLL_SYS but for the USB PLL: `configure_pll(PLL_USB, ...)` returned an error during clock init and the driver panics with the PLL error attached. The USB PLL must produce a 48 MHz clock for USB operation, and invalid divider settings from the crystal reference cause setup failure.

Solutions

  1. Confirm `config.hz` equals the actual crystal frequency on the board
  2. Use the default usb_pll config (targets 48 MHz) rather than a hand-computed value
  3. Read the `{:?}` error payload to identify whether VCO or post-divider selection failed
  4. Set `usb_pll: None` only if you do not need USB and have an alternate 48 MHz source

Example fix

// before
usb_pll: Some(96_000_000) // cannot post-divide to required USB clock from this ref
// after
usb_pll: Some(48_000_000) // standard USB PLL target from the default config
Defensive patterns

Strategy: validation

Validate before calling

fn validate_usb_pll(ref_hz: u32) -> Result<(), &'static str> {
    // USB PLL must produce exactly 48 MHz after refdiv/fbdiv/postdiv
    if ref_hz != 12_000_000 && ref_hz != 12_288_000 && ref_hz != 25_000_000 {
        return Err("unsupported crystal for default USB PLL plan");
    }
    Ok(())
}

Prevention

When it happens

Trigger: Calling clock init with a `usb_pll: Some(config)` whose frequency plan cannot be derived from `config.hz` (crystal frequency mismatch or invalid VCO/divider combination).

Common situations: Board crystal differs from the assumed 12 MHz; board code passing a custom usb_pll value that cannot hit exactly 48 MHz after post-dividers; clone/custom hardware with an unusual oscillator.

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/49c6f2265600e6ae. Report an issue: GitHub.

Appendix: source

Thrown at embassy-rp/src/clocks.rs:1117

        }
    }

    let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc {
        Some(config) => {
            // start XOSC
            start_xosc(config.hz, config.delay_multiplier);

            let pll_sys_freq = match config.sys_pll {
                Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
                    Ok(freq) => freq,
                    Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e),
                },
                None => 0,
            };
            let pll_usb_freq = match config.usb_pll {
                Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
                    Ok(freq) => freq,
                    Err(e) => panic!("Failed to configure PLL_USB: {:?}", e),
                },
                None => 0,
            };

            (config.hz, pll_sys_freq, pll_usb_freq)
        }
        None => (0, 0, 0),
    };

    CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
    CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed);
    CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed);

    let (ref_src, ref_aux, clk_ref_freq) = {
        use ClkRefCtrlAuxsrc as Aux;
        use ClkRefCtrlSrc as Src;
        let div = config.ref_clk.div as u32;
        assert!(div >= 1 && div <= 4);

View on GitHub (pinned to 463a07b963)