Description
In ports/stm32/stm32_it.c (v1.29.0), faults leave nothing behind to diagnose them with in the field:
HardFault resets silently. HardFault_C_Handler calls powerctrl_mcu_reset() first unless pyb.fault_debug(True) was set (lines 149-151). A crash in the field then looks exactly like a board that rebooted on its own, and machine.reset_cause() can't tell it apart from a software or pin reset.
The configurable faults hang. mpu.h enables MemManage (SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk), and MemManage_Handler, BusFault_Handler and UsageFault_Handler loop forever in MICROPY_BOARD_FATAL_ERROR. An MPU violation hangs the board. A hardware watchdog can reset it, but at default priorities a watchdog early-warning interrupt can't preempt the fault handler, so nothing records where the fault happened.
Proposal: an optional board hook, called before the reset. A board can save the fault to backup registers or no-init RAM and report it after reboot. When a board defines the hook, the configurable faults take the HardFault path too, so they are recorded and reset instead of hanging.
see code below
BusFault_Handler and UsageFault_Handler get the same treatment. The board side is a few lines: store pc, lr, xpsr plus SCB->CFSR and SCB->HFSR.
Tested on an STM32N657 board. An inline-asm branch to address 0 reset within 1 s and left CFSR = INVSTATE, HFSR = FORCED, PC = 0, and LR in fun_asm_call. We use this as a local patch and can open a PR if the approach is acceptable.
Code Size
void HardFault_C_Handler(ExceptionRegisters_t *regs) {
- #if defined(MICROPY_BOARD_HARD_FAULT)
- // Last chance to note where it happened: the reset below is silent.
- MICROPY_BOARD_HARD_FAULT(regs->pc, regs->lr, regs->xpsr);
- #endif
- if (!pyb_hard_fault_debug) {
powerctrl_mcu_reset();
}
+#if defined(MICROPY_BOARD_HARD_FAULT)
+// The board records faults, so the configurable ones take the HardFault
+// path too: recorded, then reset (or dumped with pyb.fault_debug()), instead
+// of a silent hang. CFSR still says which fault it was. A plain branch keeps
+// LR as EXC_RETURN for HardFault_Handler's choice of stack.
+attribute((naked)) void MemManage_Handler(void) {
- __asm volatile ("b HardFault_Handler");
+}
+#else
void MemManage_Handler(void) {
/* Go to infinite loop when Memory Manage exception occurs */
while (1) {
MICROPY_BOARD_FATAL_ERROR("MemManage");
}
}
+#endif
Implementation
I intend to implement this feature and would submit a Pull Request if desirable
Code of Conduct
Yes, I agree
Description
In ports/stm32/stm32_it.c (v1.29.0), faults leave nothing behind to diagnose them with in the field:
HardFault resets silently. HardFault_C_Handler calls powerctrl_mcu_reset() first unless pyb.fault_debug(True) was set (lines 149-151). A crash in the field then looks exactly like a board that rebooted on its own, and machine.reset_cause() can't tell it apart from a software or pin reset.
The configurable faults hang. mpu.h enables MemManage (SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk), and MemManage_Handler, BusFault_Handler and UsageFault_Handler loop forever in MICROPY_BOARD_FATAL_ERROR. An MPU violation hangs the board. A hardware watchdog can reset it, but at default priorities a watchdog early-warning interrupt can't preempt the fault handler, so nothing records where the fault happened.
Proposal: an optional board hook, called before the reset. A board can save the fault to backup registers or no-init RAM and report it after reboot. When a board defines the hook, the configurable faults take the HardFault path too, so they are recorded and reset instead of hanging.
see code below
BusFault_Handler and UsageFault_Handler get the same treatment. The board side is a few lines: store pc, lr, xpsr plus SCB->CFSR and SCB->HFSR.
Tested on an STM32N657 board. An inline-asm branch to address 0 reset within 1 s and left CFSR = INVSTATE, HFSR = FORCED, PC = 0, and LR in fun_asm_call. We use this as a local patch and can open a PR if the approach is acceptable.
Code Size
void HardFault_C_Handler(ExceptionRegisters_t *regs) {
powerctrl_mcu_reset();
}
+#if defined(MICROPY_BOARD_HARD_FAULT)
+// The board records faults, so the configurable ones take the HardFault
+// path too: recorded, then reset (or dumped with pyb.fault_debug()), instead
+// of a silent hang. CFSR still says which fault it was. A plain branch keeps
+// LR as EXC_RETURN for HardFault_Handler's choice of stack.
+attribute((naked)) void MemManage_Handler(void) {
+}
+#else
void MemManage_Handler(void) {
/* Go to infinite loop when Memory Manage exception occurs */
while (1) {
MICROPY_BOARD_FATAL_ERROR("MemManage");
}
}
+#endif
Implementation
I intend to implement this feature and would submit a Pull Request if desirable
Code of Conduct
Yes, I agree