embassy-rs/embassy · error

PLL should not be disabled / reconfigured if used for IC1…

Error message

PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)

What it means

During PLL reconfiguration on STM32N6, is_new_pll_config triggers a disable/reconfigure cycle; before doing so the driver checks whether the PLL (as Icsel n) currently feeds IC1, the CPU clock source. If the CPU is switching on IC1 whose source is this very PLL, disabling the PLL would kill the CPU clock, so it panics.

Solutions

  1. Temporarily switch the CPU clock (Cpusw to IC1 from HSI, or a different IC source) before reconfiguring the PLL
  2. Reconfigure a different PLL and only then retarget IC1 to it
  3. Avoid re-running init_config for a PLL that is the active cpuclksrc; plan the clock tree statically

Example fix

// before
config.pll1 = Some(new_pll1_cfg); // IC1/PLL1 is current CPU clock
init(config);
// after
// first: switch CPU to HSI via IC1
config.ic1 = Some(Ic1Config::from(hsi_ck));
config.cpu_source = CpuClkSource::IC1;
// then apply new PLL1 and switch IC1 back to PLL1
Defensive patterns

Strategy: validation

Validate before calling

// before re-running init_config with a changed PLL n
let cpu_src = current_cpu_sws();
let ic1_src = current_ic1_sel();
assert!(!(cpu_src == Cpusws::Ic1 && ic1_src == Icsel::from_bits(n as u8)),
        "move the CPU clock off this PLL before reconfiguring it");

Prevention

When it happens

Trigger: Applying a new rcc config where cpu_src == Cpusws::Ic1 and ic1_src equals the PLL being reconfigured (Icsel::from_bits(n)), i.e. the same PLL is both being torn down and still feeding the CPU clock.

Common situations: Changing PLL1's dividers at runtime while PLL1 is the CPU clock via IC1; re-running init_config with a modified PLL without first moving the CPU clock to a temporary source (like HSI).

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

        debug!("switching sys clock away from IC2 before PLL reconfiguration");
        let syssw = Syssw::from_bits(config.sys.to_bits());
        RCC.cfgr().modify(|w| w.set_syssw(syssw));
        while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {}
        // Return the new sys source
        RCC.cfgr().read().syssws()
    } else {
        sys_src
    };

    for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() {
        debug!("configuring PLL{}", n + 1);
        let pll_ready = RCC.sr().read().pllrdy(n);

        if is_new_pll_config(pll, n) {
            let this_pll = Icsel::from_bits(n as u8);

            if cpu_src == Cpusws::Ic1 && ic1_src == this_pll {
                panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)")
            }

            if sys_src == Syssws::Ic2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) {
                panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)")
            }

            *out = pll.map_or_else(
                || {
                    disable_pll(n);
                    PllOutput::default()
                },
                |c| init_pll(Some(c), n, &pll_input),
            );
        } else if pll.is_some() {
            // Config matches current register state.
            *out = pll_output(pll, &pll_input);
            if !pll_ready {
                RCC.csr().write(|w| w.set_pllons(n, true));

View on GitHub (pinned to 463a07b963)