Printer model
Core One L (error surfaces on Core One as well — see analysis below)
Firmware version
6.5.3+12780 (current). Originally seen on 6.5.2 (factory firmware on the Core One L, exact build unknown); updated to 6.5.3+12780 hoping to fix it, still reproduces. Bug present in code on all POWER_PANIC-enabled printers since 0050cb43a (2025-02-12).
Upgrades and modifications
N/A — issue is in stock firmware
Printing from
N/A — fault fires at boot, before any print
Describe the bug
On boot, the printer intermittently displays the orange "Power Panic" error screen with ERR_ELECTRO_ACF_AT_INIT ("Power panic detected on startup. Check power panic cable.") — on Core One L this maps to help article #35338 "AC Controller Fault" (prusa.io/35338). Multiple resets (sometimes 6-7) are needed to clear the condition. No crash dump is generated.
Your help article acknowledges sporadic occurrences may be firmware-related. The analysis below confirms it.
How to reproduce
Power cycle the printer repeatedly. On some boots (intermittent, ~1 in every few to every few dozen depending on unit) the error fires instead of reaching the home screen.
TL;DR
check_ac_fault_at_startup() reads the acFault GPIO pin once with no debounce or retry, triggering ERR_ELECTRO_ACF_AT_INIT on transient power-on glitches. The pin is configured Pull::none, meaning it floats until the AC monitoring circuit drives it. On Core One, this causes intermittent false-positive "Power Panic" errors at boot, sometimes requiring 6-7 resets.
I'd like to propose adding a retry loop with settling delay as a workaround. Happy to send a PR — wanted to flag the pin configuration and history first, since the root cause may warrant Pull::up instead of (or in addition to) software debounce.
All file references in this issue are permalinks pinned to b91eeda0c so they survive line-number drift.
The Pull::up removal argument
The acFault pin originally had a pull-up resistor configured in software. In c9b365bc4 (2024-06-20, "iX: Enable Power Panic", BFW-4751), the pin was converted from InputPin + Pull::up to InterruptPin + Pull::none (schematic — macro arguments elided for readability):
-MACRO_FUNCTION(buddy::hw::InputPin, acFault, ..., IMode::input COMMA Pull::up, buddy::hw::noHandler)
+MACRO_FUNCTION(buddy::hw::InterruptPin, acFault, ..., IMode::IT_falling COMMA Pull::none COMMA ISR_PRIORITY_POWER_PANIC COMMA 0, power_panic::ac_fault_isr)
The stated intent was enabling interrupt-driven power panic on iX. The Pull::up removal was a side effect of the pin type change. With Pull::up, a floating pin reads HIGH (no fault) — safe during power-on transients. With Pull::none, a floating pin is indeterminate and may read LOW (fault).
Eight months later, 0050cb43a (2025-02-12, "Show nice ACF_AT_INIT for all relevant printers", BFW-6768) removed the printer-type guard that limited the check to XL/MK4/MK3.5, extending it to all POWER_PANIC printers including Core One. Neither debounce nor Pull::up was considered.
The two-commit interaction: one removed the hardware safety net, the other expanded the check to printers with potentially different monitoring circuit timing. Neither introduced compensation.
History — how the false positive was introduced
The startup check was established in 2e4ee6679 (2023-05-26, v5.0.0-alpha1). It was a single is_ac_fault_active() call guarded by if constexpr to fire only on XL/MK4/MK3.5. The code included a TODO: "AC-fault during initialization //TODO: IXL Remove if after PP is ready".
c9b365bc4 (2024-06-20) changed the pin from Pull::up to Pull::none. The commit's stated intent was enabling power panic on iX. The pull-up change was not discussed in the commit message. This is the commit that removed the protection against transient reads.
0050cb43a (2025-02-12) removed the printer-type conditional. BFW-6768's stated intent was showing the error on all relevant printers. The commit is -8/+2 lines — purely removing the guard. No debounce was added.
git log -S 'check_ac_fault_at_startup' since then shows only 0050cb43a itself. No one has touched the debounce gap in the 14 months since the pull-up was removed.
Why the current design fails
Three concrete failure surfaces with the current code:
-
Floating pin at power-on. hwio_pindef.h:389. Pin PG0 configured Pull::none, IMode::IT_falling. Between GPIO init (main.cpp:239) and AC monitoring circuit stabilization, the pin state is indeterminate. A Pull::none pin with no external pull-up may read LOW (fault) on noise alone.
-
Single read, immediate fatal_error. power_panic.cpp:812-817. One GPIO read → fatal_error(). No second opinion, no settling delay. A transient LOW on a Pull::none pin is treated identically to a persistent AC fault.
-
Confirmed by users and Prusa. Your own help article (#35338) states: "if the error occurs sporadically and resolves itself without user intervention, it may point to a firmware-related issue." Users report needing 6-7 resets to clear the condition, confirming the transient window is wide.
Caller trace
Two production call sites for is_ac_fault_active():
-
power_panic.cpp:813 — check_ac_fault_at_startup(). Called once at boot from main.cpp:501. Only when POWER_PANIC is enabled (MK4, MK3.5, iX, XL, COREONE). IWDG watchdog is not yet running at this point — verified in wdt.cpp (IWDG init happens later in Marlin's setup()).
-
modular_bed.cpp:130 — runtime guard in ModularBed::read_general_status(). Only on modular-bed printers (XL/iX), not Core One. Well after boot, GPIO long settled. Not affected.
The ac_fault_isr() at power_panic.cpp:825 is armed during GPIO init but gated by ac_fault_enabled (set true only after the startup check). The ISR provides ongoing protection after boot — it is not affected by the startup transient issue.
If there's a caller I missed — especially one where the pin is read before GPIO initialization is complete — I'd want to hear about it.
Proposal
Software workaround (ready to PR): Add a retry loop to check_ac_fault_at_startup() — 5 retries × 200ms = 1s max settling window. Genuine faults persist; transients clear. Uses delay_ms() from timing.h — already included in power_panic.cpp (line 67), same family as the delay_us_precise() already used elsewhere in this file (line 798). Busy-wait on the project's ticks_ms timer, no FreeRTOS scheduler dependency. Net diff: +6 lines. The IWDG watchdog is not running at this point in boot, so the 1s delay carries no watchdog risk.
void check_ac_fault_at_startup() {
for (int i = 0; i < 5 && power_panic::is_ac_fault_active(); ++i) {
delay_ms(200);
}
if (power_panic::is_ac_fault_active()) {
fatal_error(ErrCode::ERR_ELECTRO_ACF_AT_INIT);
}
ac_fault_enabled = true;
}
Hardware-level question for your team: Would restoring Pull::up on the acFault pin be appropriate? The pull-up was present before c9b365bc4 and would keep the pin HIGH (non-fault) during the transient window without needing software debounce. I don't know whether the AC monitoring circuit's output stage is compatible with an internal pull-up, so this is a question rather than a recommendation.
What this is NOT
This is not a root cause fix. Without an oscilloscope trace of PG0 during Core One boot, the exact cause of the transient LOW is undiagnosed. The retry loop tolerates the symptom. Possible root causes include: floating Pull::none pin before the monitoring circuit drives it, active fault assertion during monitoring circuit initialization, or power sequencing differences between printers. The software debounce works for all of these.
This is not a boot sequence reorder. The acFault pin is direct GPIO on the main STM32, not managed by a puppy controller. Moving the check after puppy init (main.cpp:508) would not help.
PR: #5254
Printer model
Core One L (error surfaces on Core One as well — see analysis below)
Firmware version
6.5.3+12780 (current). Originally seen on 6.5.2 (factory firmware on the Core One L, exact build unknown); updated to 6.5.3+12780 hoping to fix it, still reproduces. Bug present in code on all
POWER_PANIC-enabled printers since0050cb43a(2025-02-12).Upgrades and modifications
N/A — issue is in stock firmware
Printing from
N/A — fault fires at boot, before any print
Describe the bug
On boot, the printer intermittently displays the orange "Power Panic" error screen with
ERR_ELECTRO_ACF_AT_INIT("Power panic detected on startup. Check power panic cable.") — on Core One L this maps to help article #35338 "AC Controller Fault" (prusa.io/35338). Multiple resets (sometimes 6-7) are needed to clear the condition. No crash dump is generated.Your help article acknowledges sporadic occurrences may be firmware-related. The analysis below confirms it.
How to reproduce
Power cycle the printer repeatedly. On some boots (intermittent, ~1 in every few to every few dozen depending on unit) the error fires instead of reaching the home screen.
TL;DR
check_ac_fault_at_startup()reads theacFaultGPIO pin once with no debounce or retry, triggeringERR_ELECTRO_ACF_AT_INITon transient power-on glitches. The pin is configuredPull::none, meaning it floats until the AC monitoring circuit drives it. On Core One, this causes intermittent false-positive "Power Panic" errors at boot, sometimes requiring 6-7 resets.I'd like to propose adding a retry loop with settling delay as a workaround. Happy to send a PR — wanted to flag the pin configuration and history first, since the root cause may warrant
Pull::upinstead of (or in addition to) software debounce.All file references in this issue are permalinks pinned to
b91eeda0cso they survive line-number drift.The Pull::up removal argument
The
acFaultpin originally had a pull-up resistor configured in software. Inc9b365bc4(2024-06-20, "iX: Enable Power Panic", BFW-4751), the pin was converted fromInputPin + Pull::uptoInterruptPin + Pull::none(schematic — macro arguments elided for readability):The stated intent was enabling interrupt-driven power panic on iX. The
Pull::upremoval was a side effect of the pin type change. WithPull::up, a floating pin reads HIGH (no fault) — safe during power-on transients. WithPull::none, a floating pin is indeterminate and may read LOW (fault).Eight months later,
0050cb43a(2025-02-12, "Show nice ACF_AT_INIT for all relevant printers", BFW-6768) removed the printer-type guard that limited the check to XL/MK4/MK3.5, extending it to allPOWER_PANICprinters including Core One. Neither debounce norPull::upwas considered.The two-commit interaction: one removed the hardware safety net, the other expanded the check to printers with potentially different monitoring circuit timing. Neither introduced compensation.
History — how the false positive was introduced
The startup check was established in
2e4ee6679(2023-05-26, v5.0.0-alpha1). It was a singleis_ac_fault_active()call guarded byif constexprto fire only on XL/MK4/MK3.5. The code included a TODO:"AC-fault during initialization //TODO: IXL Remove if after PP is ready".c9b365bc4(2024-06-20) changed the pin fromPull::uptoPull::none. The commit's stated intent was enabling power panic on iX. The pull-up change was not discussed in the commit message. This is the commit that removed the protection against transient reads.0050cb43a(2025-02-12) removed the printer-type conditional. BFW-6768's stated intent was showing the error on all relevant printers. The commit is -8/+2 lines — purely removing the guard. No debounce was added.git log -S 'check_ac_fault_at_startup'since then shows only0050cb43aitself. No one has touched the debounce gap in the 14 months since the pull-up was removed.Why the current design fails
Three concrete failure surfaces with the current code:
Floating pin at power-on.
hwio_pindef.h:389. Pin PG0 configuredPull::none, IMode::IT_falling. Between GPIO init (main.cpp:239) and AC monitoring circuit stabilization, the pin state is indeterminate. APull::nonepin with no external pull-up may read LOW (fault) on noise alone.Single read, immediate fatal_error.
power_panic.cpp:812-817. One GPIO read →fatal_error(). No second opinion, no settling delay. A transient LOW on aPull::nonepin is treated identically to a persistent AC fault.Confirmed by users and Prusa. Your own help article (#35338) states: "if the error occurs sporadically and resolves itself without user intervention, it may point to a firmware-related issue." Users report needing 6-7 resets to clear the condition, confirming the transient window is wide.
Caller trace
Two production call sites for
is_ac_fault_active():power_panic.cpp:813—check_ac_fault_at_startup(). Called once at boot frommain.cpp:501. Only whenPOWER_PANICis enabled (MK4, MK3.5, iX, XL, COREONE). IWDG watchdog is not yet running at this point — verified inwdt.cpp(IWDG init happens later in Marlin'ssetup()).modular_bed.cpp:130— runtime guard inModularBed::read_general_status(). Only on modular-bed printers (XL/iX), not Core One. Well after boot, GPIO long settled. Not affected.The
ac_fault_isr()atpower_panic.cpp:825is armed during GPIO init but gated byac_fault_enabled(set true only after the startup check). The ISR provides ongoing protection after boot — it is not affected by the startup transient issue.If there's a caller I missed — especially one where the pin is read before GPIO initialization is complete — I'd want to hear about it.
Proposal
Software workaround (ready to PR): Add a retry loop to
check_ac_fault_at_startup()— 5 retries × 200ms = 1s max settling window. Genuine faults persist; transients clear. Usesdelay_ms()fromtiming.h— already included inpower_panic.cpp(line 67), same family as thedelay_us_precise()already used elsewhere in this file (line 798). Busy-wait on the project'sticks_mstimer, no FreeRTOS scheduler dependency. Net diff: +6 lines. The IWDG watchdog is not running at this point in boot, so the 1s delay carries no watchdog risk.Hardware-level question for your team: Would restoring
Pull::upon theacFaultpin be appropriate? The pull-up was present beforec9b365bc4and would keep the pin HIGH (non-fault) during the transient window without needing software debounce. I don't know whether the AC monitoring circuit's output stage is compatible with an internal pull-up, so this is a question rather than a recommendation.What this is NOT
This is not a root cause fix. Without an oscilloscope trace of PG0 during Core One boot, the exact cause of the transient LOW is undiagnosed. The retry loop tolerates the symptom. Possible root causes include: floating
Pull::nonepin before the monitoring circuit drives it, active fault assertion during monitoring circuit initialization, or power sequencing differences between printers. The software debounce works for all of these.This is not a boot sequence reorder. The
acFaultpin is direct GPIO on the main STM32, not managed by a puppy controller. Moving the check after puppy init (main.cpp:508) would not help.PR: #5254