#ifndef FAULT_HANDLER_H #define FAULT_HANDLER_H #include #include /* * fault_handler.h — STM32F7 fault detection and recovery (Issue #565) * * Features: * - HardFault / BusFault / UsageFault / MemManage vector hooks with full * Cortex-M7 register dump (R0-R3, LR, PC, xPSR, CFSR, HFSR, MMFAR, BFAR) * - .noinit SRAM ring: fault frame captured and magic-tagged, survives * NVIC_SystemReset(); persisted to flash on the subsequent boot * - MPU Region 0 stack-guard (32 bytes at __stack_end, no-access) → MemManage * fault detected as FAULT_STACK_OVF * - Brownout detect via RCC_CSR_BORRSTF on boot → FAULT_BROWNOUT * - Persistent fault log: last 8 entries × 64 bytes in flash sector 7 * at 0x08060000 (below the PID store at 0x0807FFC0) * - JLINK_TLM_FAULT_LOG (0x85): 20-byte summary sent via JLink on boot * and on JLINK_CMD_FAULT_LOG_GET (0x0C) request * - LED blink codes on LED2 (PC14, active-low) for 10 s after recovery: * HARDFAULT = 3 fast blinks (100 ms) * WATCHDOG = 2 slow blinks (300 ms) * BROWNOUT = 1 long blink (500 ms) * STACK_OVF = 4 fast blinks (100 ms) * BUS_FAULT = alternating 3+1 * USAGE_FAULT = 2 fast blinks * - Auto-recovery: fault → .noinit capture → NVIC_SystemReset() * On next boot fault_handler_init() re-runs safely: persists, prints, blinks * * Flash layout within sector 7 (0x08060000, 128 KB): * Slot 0-7: 0x08060000 – 0x080601FF (8 × 64 bytes = 512 bytes fault log) * PID store: 0x0807FFC0 – 0x0807FFFF (64 bytes, managed by pid_flash.c) */ /* ---- Fault types ---- */ typedef enum { FAULT_NONE = 0x00, FAULT_HARDFAULT = 0x01, /* HardFault escalation */ FAULT_WATCHDOG = 0x02, /* IWDG timeout reset */ FAULT_BROWNOUT = 0x03, /* Brown-out reset (BOR) */ FAULT_STACK_OVF = 0x04, /* MPU stack guard MemManage */ FAULT_BUS_FAULT = 0x05, /* BusFault */ FAULT_USAGE_FAULT = 0x06, /* UsageFault */ FAULT_MEM_FAULT = 0x07, /* MemManageFault (non-stack-guard) */ FAULT_ASSERT = 0x08, /* Software assertion */ } FaultType; /* ---- Flash fault log constants ---- */ #define FAULT_LOG_MAX_ENTRIES 8u #define FAULT_LOG_MAGIC 0xFADE5A01u #define FAULT_LOG_BASE_ADDR 0x08060000UL /* start of flash sector 7 */ #define FAULT_LOG_ENTRY_SIZE 64u /* bytes per entry */ /* ---- Flash fault log entry (64 bytes, packed) ---- */ typedef struct __attribute__((packed)) { uint32_t magic; /* FAULT_LOG_MAGIC when valid */ uint8_t fault_type; /* FaultType */ uint8_t reset_count; /* lifetime reset counter */ uint16_t _pad0; uint32_t timestamp_ms; /* HAL_GetTick() at reset (0 if pre-tick) */ uint32_t pc; /* faulting instruction address */ uint32_t lr; /* link register at fault */ uint32_t r0; uint32_t r1; uint32_t r2; uint32_t r3; uint32_t cfsr; /* SCB->CFSR: combined fault status register */ uint32_t hfsr; /* SCB->HFSR: hard fault status register */ uint32_t mmfar; /* SCB->MMFAR: memory manage fault address */ uint32_t bfar; /* SCB->BFAR: bus fault address */ uint32_t sp; /* stack pointer value at fault */ uint8_t _pad1[4]; /* pad to 64 bytes */ } fault_log_entry_t; /* 64 bytes */ /* * fault_handler_init() — call early in main(), before safety_init(). * 1. Increments reset counter (.noinit SRAM). * 2. Checks .noinit SRAM for a pending fault capture; if found: persists to * flash, prints CDC register dump, starts LED blink code. * 3. Detects brownout via RCC_CSR_BORRSTF; logs if detected. * 4. Clears RCC reset flags. * 5. Installs MPU Region 0 stack guard. * 6. Enables MemManage, BusFault, UsageFault (SCB->SHCSR). */ void fault_handler_init(void); /* * fault_mpu_guard_init() — configure MPU Region 0 as a 32-byte no-access * guard at __stack_end (bottom of main stack). Generates MemManage on * stack overflow. Called automatically by fault_handler_init(). */ void fault_mpu_guard_init(void); /* * fault_get_last_type() — most recent fault type from flash log, or FAULT_NONE. */ FaultType fault_get_last_type(void); /* * fault_log_read(idx, out) — read flash slot 0..7. * Returns false if slot empty or idx out of range. */ bool fault_log_read(uint8_t idx, fault_log_entry_t *out); /* * fault_log_get_count() — number of valid (occupied) log slots, 0-8. */ uint8_t fault_log_get_count(void); /* * fault_log_clear() — erase fault log, restore PID if previously saved. * Erases all of sector 7 (~1 s stall). Do not call while armed. */ void fault_log_clear(void); /* * fault_assert(file, line) — software fault at runtime; captures return * address, writes SRAM magic, triggers NVIC_SystemReset(). * Use via FAULT_ASSERT(cond) macro below. */ void fault_assert_impl(const char *file, int line); #define FAULT_ASSERT(cond) \ do { if (!(cond)) fault_assert_impl(__FILE__, __LINE__); } while (0) /* * fault_led_tick(now_ms) — drive LED2 blink code from main loop (1 ms). * Self-disables after 10 s so it doesn't interfere with normal LED state. */ void fault_led_tick(uint32_t now_ms); /* C-level fault dispatch (called from naked asm stubs; not for direct use) */ void fault_hard_c(uint32_t *frame); void fault_mem_c(uint32_t *frame); void fault_bus_c(uint32_t *frame); void fault_usage_c(uint32_t *frame); #endif /* FAULT_HANDLER_H */