embassy-rs/embassy · error

When the HSE is used as cpu/system bus clock or clock…

Error message

When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled

What it means

embassy-stm32's HSE disable path for STM32N6 checks whether HSE is still in use as the cpu/system bus clock or as the input of any running PLL (pllrdy). If so, hardware rules forbid turning HSE off, and the driver panics instead of killing the active clock tree.

Solutions

  1. Switch sysclk to another source and disable/stop all PLLs using HSE before disabling HSE
  2. Reorder the shutdown sequence: stop PLL1-4 first (wait pllrdy clear), then turn off HSE
  3. If HSE must keep running, skip the HSE-disable step

Example fix

// before
disable_hse(); // PLL1 still running off HSE
// after
stop_pll(0); // clear PL1ON, wait PLL1RDY == 0
switch_sysclk_to_hsi();
disable_hse();
Defensive patterns

Strategy: validation

Validate before calling

fn hse_in_use() -> bool {
    // true if sysclk is HSE or any ready PLL is fed by HSE
    sysclk_is(Syssws::Hse) || (0..4).any(|n| pll_ready(n) && pll_source(n) == Pllsel::Hse)
}
assert!(!hse_in_use(), "stop PLLs / switch sysclk before disabling HSE");

Prevention

When it happens

Trigger: Calling the HSE-off code path (e.g. deinit/low-power entry that disables HSE) while: sys clock source is HSE, or any of PLL1..PLL4 is running (pllrdy set) with HSE selected as its input.

Common situations: Entering Stop/standby-style low-power code that unconditionally disables HSE; runtime reconfiguration switching sysclk but leaving PLLs clocked from HSE; dropping an RCC config that assumed PLLs were already off.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/729ad0f0f1db5a89. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/rcc/n6.rs:937

                    w.set_hsebyp(true);
                    w.set_hseext(Hseext::Digital);
                });
            }
        }
        RCC.csr().write(|w| w.set_hseons(true));

        // wait until the hse is ready
        while !RCC.sr().read().hserdy() {}

        Some(hse.freq)
    } else if cpu_src == Cpusws::Hse
        || sys_src == Syssws::Hse
        || (pll1_src == Pllsel::Hse && rcc_sr.pllrdy(0))
        || (pll2_src == Pllsel::Hse && rcc_sr.pllrdy(1))
        || (pll3_src == Pllsel::Hse && rcc_sr.pllrdy(2))
        || (pll4_src == Pllsel::Hse && rcc_sr.pllrdy(3))
    {
        panic!(
            "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
        );
    } else {
        debug!("HSE off");

        RCC.ccr().write(|w| w.set_hseonc(true));
        RCC.hsecfgr().modify(|w| {
            w.set_hseext(Hseext::Analog);
            w.set_hsebyp(false);
        });

        // wait until the hse is disabled
        while RCC.sr().read().hserdy() {}

        None
    };
    // hse rtc configuration
    let hse_rtc = hse.map(|freq| freq / (RCC.ccipr7().read().rtcpre().to_bits() + 1));

View on GitHub (pinned to 463a07b963)