Files
PLFM_RADAR/9_Firmware/9_1_Microcontroller
Jason 534905263f mcu(health): poll PD15 + dispatch ERROR_FPGA_DSP_STALL (AUDIT-S10 follow-up)
AUDIT-S10 (commit `58154a6`) split the FPGA's six-flag aggregate
gpio_dig5 into two MCU-visible bits: gpio_dig5 keeps signal-saturation
(AGC reacts), gpio_dig7 (PD15) carries control-fault classes
(range_decim_watchdog | cic_fir_overrun). Until now the MCU did NOT
poll PD15, so DSP control faults were invisible to the recovery
dispatcher.

Changes:

- New `ERROR_FPGA_DSP_STALL` enum value placed AFTER ERROR_WATCHDOG_TIMEOUT
  so the dispatcher routes to attemptErrorRecovery (FPGA reset pulse) not
  Emergency_Stop. Updated error_strings[] in lockstep (static_assert
  enforces).

- checkSystemHealth section 10 polls PD15 at 1 Hz with 2-sample debounce.
  `last_dsp_check` is committed BEFORE the early return per AUDIT-CAL
  pattern, so a flapping fault never bypasses the rate-limit. Streak
  counter resets to 0 after firing (armed for next post-recovery
  assertion) AND resets naturally when PD15 returns LOW.

- attemptErrorRecovery: ERROR_FPGA_DSP_STALL fans into the existing
  ERROR_FPGA_COMM PD12 reset case (stacked case labels, same body). No
  MCU-driven reset_monitors path exists; full bitstream reload clears
  all sticky monitors as a side effect.

Tests:
- tests/test_audit_s10_dsp_stall_polling.c (NEW, 7 scenarios, 7/7 PASS):
  T1 healthy 60s, T2 single-sample glitch blocked by debounce, T3
  sustained fault fires once, T4 post-fire rate-limit holds within
  window, T5 sustained fault rate bounded (29 errors / 60s -- MCU-N1
  latch at error_count>10 fires in ~22s, gives operator time to
  intervene), T6 counter-test demos no-debounce false-positive on
  glitch, T7 HAL_GetTick 32-bit wrap.
- MCU host suite 35/35 PASS (was 34/34; +1 new, 0 regressions).
2026-04-29 23:42:21 +05:45
..