Archive STM32 firmware to legacy/stm32/: - src/, include/, lib/USB_CDC/, platformio.ini, test stubs, flash_firmware.py - test/test_battery_adc.c, test_hw_button.c, test_pid_schedule.c, test_vesc_can.c, test_can_watchdog.c - USB_CDC_BUG.md Rename: stm32_protocol → esp32_protocol, mamba_protocol → balance_protocol, stm32_cmd_node → esp32_cmd_node, stm32_cmd_params → esp32_cmd_params, stm32_cmd.launch.py → esp32_cmd.launch.py, test_stm32_protocol → test_esp32_protocol, test_stm32_cmd_node → test_esp32_cmd_node Content cleanup across all files: - Mamba F722S → ESP32-S3 BALANCE - BlackPill → ESP32-S3 IO - STM32F722/F7xx → ESP32-S3 - stm32Mode/Version/Port → esp32Mode/Version/Port - STM32 State/Mode labels → ESP32 State/Mode - Jetson Nano → Jetson Orin Nano Super - /dev/stm32 → /dev/esp32 - stm32_bridge → esp32_bridge - STM32 HAL → ESP-IDF docs/SALTYLAB.md: - Update "Drone FC Details" to describe ESP32-S3 BALANCE board (Waveshare ESP32-S3 Touch LCD 1.28) - Replace verbose "Self-Balancing Control" STM32 section with brief note pointing to SAUL-TEE-SYSTEM-REFERENCE.md TEAM.md: Update Embedded Firmware Engineer role to ESP32-S3 / ESP-IDF No new functionality — cleanup only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
141 lines
5.4 KiB
C
141 lines
5.4 KiB
C
#ifndef FAULT_HANDLER_H
|
||
#define FAULT_HANDLER_H
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
|
||
/*
|
||
* 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 */
|