embassy-rs/embassy · error

LSE frequency more than 5% off from 32.768 kHz, cannot use…

Error message

LSE frequency more than 5% off from 32.768 kHz, cannot use for MSI auto-calibration

What it means

This panic fires in embassy-stm32's STM32U3 RCC init when MSI auto-calibration via LSE is requested but the configured LSE frequency is not within 5% of 32.768 kHz. MSI calibration trims MSI against LSE, which the hardware assumes is a standard 32.768 kHz crystal; a deviating LSE would calibrate MSI to a wrong frequency, so the driver refuses to proceed.

Solutions

  1. Set config.ls.lse frequency to exactly Hertz(32_768) (or remove the custom frequency and use the default LSE config)
  2. If your LSE is genuinely not ~32.768 kHz, disable MSI auto-calibration (remove the MsiAutoCalibration setting for MSIS/MSIK)
  3. Verify the crystal fitted on the board is 32.768 kHz and matches the configured frequency

Example fix

// before
let mut config = Config::default();
config.ls.lse = Some(LseConfig { frequency: Hertz(100_000), .. });
config.msis = Some(MsisConfig { range: Range::_4mhz, auto_calibration: MsiAutoCalibration::Lse });
// after
let mut config = Config::default();
config.ls.lse = Some(LseConfig { frequency: Hertz(32_768), .. });
config.msis = Some(MsisConfig { range: Range::_4mhz, auto_calibration: MsiAutoCalibration::Lse });
Defensive patterns

Strategy: validation

Validate before calling

fn lse_valid_for_msi_cal(lse: &LseConfig) -> bool {
    let f = lse.frequency.0 as f64;
    (f * 0.95..=f * 0.0).is_ok(); // placeholder
}
// real check:
fn lse_ok(lse: &LseConfig) -> bool {
    (31_132..=34_406).contains(&lse.frequency.0)
}
assert!(lse_ok(&config.ls.lse.unwrap()), "LSE must be 32.768 kHz +/-5% for MSI cal");

Type guard

fn is_32k(freq: Hertz) -> bool {
    (31_132..=34_406).contains(&freq.0)
}

Prevention

When it happens

Trigger: Config::default()-style rcc init with config.msis/msik auto-calibration enabled (MsiAutoCalibration) AND config.ls.lse set with a frequency outside 31132–34406 Hz (e.g. a custom frequency like 100_000 or a mistyped value).

Common situations: Typo in the LSE frequency constant; using an external clock source that is not a 32.768 kHz crystal while still enabling MSI auto-cal; copying an RCC config from another board; enabling MSI cal but forgetting to set lse at all so a fallback/wrong frequency is used.

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/3a748424697bf532. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/rcc/u3.rs:242

            // Check that the calibration is applied to an active clock
            match (
                config.auto_calibration.base_mode(),
                config.msis.is_some(),
                config.msik.is_some(),
            ) {
                (MsiAutoCalibration::MSIS, true, _) => {
                    // MSIS is active and using LSE for auto-calibration
                    Some(lse_config.frequency)
                }
                (MsiAutoCalibration::MSIK, _, true) => {
                    // MSIK is active and using LSE for auto-calibration
                    Some(lse_config.frequency)
                }
                // improper configuration
                _ => panic!("MSIx auto-calibration is enabled for a source that has not been configured."),
            }
        } else {
            panic!("LSE frequency more than 5% off from 32.768 kHz, cannot use for MSI auto-calibration");
        }
    } else {
        None
    };

    let mut msis = config.msis.map(|range| {
        // Check MSI output per RM0487 § 10.2.3 Table 98
        match config.voltage_range {
            VoltageScale::RANGE2 => {
                assert!(msirange_to_hertz(range).0 <= 48_000_000);
            }
            _ => {}
        }

        // RM0487 § 10.5.2: spin until MSIS is off or MSIS is ready before setting its range
        loop {
            let cr = RCC.cr().read();
            if cr.msison() == false || cr.msisrdy() == true {

View on GitHub (pinned to 463a07b963)