Repository navigation
Add debug LED fault signals - #335
ethanmathias merged 20 commits into
Conversation
…verflows' of https://github.com/solarcaratuva/Rivanna3S into 204-add-debug-led-signaling-for-hard-faults-and-stack-overflows
| #include "fatfs_sd.h" | ||
| #include "LedFault.h" | ||
| /* Telemetry supplies the SD timer; other boards do not use FATFS. */ | ||
| __attribute__((weak)) void SD_TimerProc(void) {} |
There was a problem hiding this comment.
This is outside #204's scope: it removes #include "fatfs_sd.h" and adds a weak SD_TimerProc stub. If Telemetry's H7 build relied on that header for the declaration, the SD_TimerProc(); call at line 199 now depends on this local stub, and the stub shadows the header's prototype. The G4 file already has the weak stub (stm32g4xx_it.c:27), but it keeps the include. Revert the include removal unless the build requires it, and say why in the PR.
| void HardFault_Handler(void) | ||
| { | ||
| /* USER CODE BEGIN HardFault_IRQn 0 */ | ||
| LedFault_halt(LedFault_HardFault); |
There was a problem hiding this comment.
Each handler now calls the noreturn LedFault_halt, so the while (1) below it is dead code, and the stock "NMI_Handler 1" while (1) after the NMI call is dead too. A reader will wonder which one runs. The PR body also says "LED wiring needs a bench check" and leaves Testing empty, so none of this has run on hardware.
|
@RyanS4 Structure is good, the three callers into one
static void spin_ms(uint32_t ms) {
uint32_t loops = (SystemCoreClock / 4000U) * ms;
while (loops-- != 0U) { __NOP(); }
}
Below is chat advice for register mapping:
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_USGFAULTENA_Msk;To test: |
| #include "fatfs_sd.h" | ||
| #include "LedFault.h" | ||
| /* Telemetry supplies the SD timer; other boards do not use FATFS. */ | ||
| __attribute__((weak)) void SD_TimerProc(void) {} |
There was a problem hiding this comment.
Out of scope for the LED fault work (#204): swapping #include "fatfs_sd.h" for a weak SD_TimerProc stub changes the H7 build. If it's needed to link, say so in the PR. If not, revert it. The G4 file already has the same stub at stm32g4xx_it.c:26-27, so the pattern matches, but it belongs in its own change.
| #include "fatfs_sd.h" | ||
| #include "LedFault.h" | ||
| /* Telemetry supplies the SD timer; other boards do not use FATFS. */ | ||
| __attribute__((weak)) void SD_TimerProc(void) {} |
There was a problem hiding this comment.
This is out of scope for the debug-LED issue (#204). It removes the fatfs_sd.h include and adds a weak SD_TimerProc stub. The change does match the G4 file (stm32g4xx_it.c:25-27), so it may be fine, but it should go in its own PR. Alternatively, say in the PR description why it is needed.
|
|
||
| /* Private user code ---------------------------------------------------------*/ | ||
| /* USER CODE BEGIN 0 */ | ||
| void SecureFault_Handler(void) |
There was a problem hiding this comment.
SecureFault_Handler is never enabled. startup.cpp sets MEMFAULTENA, BUSFAULTENA and USGFAULTENA but not SCB_SHCSR_SECUREFAULTENA_Msk, so a secure fault will not reach this handler. This is untested (the PR lists no 8-blink test). Either enable it for U5 in startup.cpp, with a comment, or drop the handler and LedFault_SecureFault.
|
Review: 5 inline comments posted. Main points: name the PC1 pin and blink-timing constants and document the |
| // Debug LED. PC1 matches MotorBoard's DEBUG_OUT (G474 build) and LED1 in | ||
| // log.cpp; unconfirmed on the other boards. | ||
| #define DEBUG_LED_PORT GPIOC | ||
| #define DEBUG_LED_PIN GPIO_PIN_1 |
There was a problem hiding this comment.
The LED pin is hardcoded to PC1 for every board, and the comment admits it is "unconfirmed on the other boards". On any board where PC1 is something else (e.g. MotorBoard/Inc/pindef.h:44 defines DEBUG_OUT as NC for the other build), a fault handler will reconfigure that pin as a push-pull output and drive it. The repo defines per-board pins in each board's Inc/pindef.h (MotorBoard/Inc/pindef.h:14). Take the port and pin from a per-board define, or build the fault LED only for boards where it is confirmed. A new member debugging a different board should not have to guess whether PC1 is safe.
| extern "C" { | ||
| #endif | ||
|
|
||
| /** |
There was a problem hiding this comment.
This doc block is garbled. "Fault code determining the number of blinks per cycle." is a dangling fragment with no @param, and the LedFault_halt_assert block starts mid-sentence ("LedFault_halt(...), as a plain void(void) entry point"). Make them complete sentences, e.g. @param fault Number of blinks per cycle., and start the second with "Calls LedFault_halt(LedFault_RTOSAssert) ...".
| #include "fatfs_sd.h" | ||
| #include "LedFault.h" | ||
| /* Telemetry supplies the SD timer; other boards do not use FATFS. */ | ||
| __attribute__((weak)) void SD_TimerProc(void) {} |
There was a problem hiding this comment.
Out of scope for debug LED faults: this removes #include "fatfs_sd.h" and adds a weak SD_TimerProc stub. It is unrelated to #204. Drop it from this PR, or put it in its own PR with the reason. If fatfs_sd.h is still needed for the SD_TimerProc() call at line 199, the build may also break.
| // Debug LED. PC1 matches MotorBoard's DEBUG_OUT (G474 build) and LED1 in | ||
| // log.cpp; unconfirmed on the other boards. | ||
| #define DEBUG_LED_PORT GPIOC | ||
| #define DEBUG_LED_PIN GPIO_PIN_1 |
There was a problem hiding this comment.
PC1 is hardcoded for every board, and the comment admits it's "unconfirmed on the other boards". Issue #204 says to take the LED pins from each board's pindef (DEBUG_OUT) and confirm per board. On a board where PC1 is something else, this fault handler would drive an unrelated pin. Either get the pin from the board's pindef, or confirm PC1 on the H743 and U5A9 boards and say so here.
|
|
||
| // Repeatedly blink the fault count, pausing between cycles. | ||
| while (true) { | ||
| for (unsigned pulse = 0; pulse < static_cast<unsigned>(fault); ++pulse) { |
There was a problem hiding this comment.
200U and 1500U are the blink timing, but they are bare literals. Name them next to the DEBUG_LED_* defines, e.g. BLINK_INTERVAL_MS and REPEAT_PAUSE_MS. The units are then obvious, and the timing can be changed in one place.
| #include "fatfs_sd.h" | ||
| #include "LedFault.h" | ||
| /* Telemetry supplies the SD timer; other boards do not use FATFS. */ | ||
| __attribute__((weak)) void SD_TimerProc(void) {} |
There was a problem hiding this comment.
Swapping #include "fatfs_sd.h" for a weak SD_TimerProc stub is unrelated to the debug LED issue. It is also a behavior change on H7. If it is needed to make the build work, say why in the PR description. Otherwise, leave it out of this PR.
Summary
Adds debug LED patterns for hard faults, stack overflows, and other faults.
Testing
Verified all 8 terminal fault blink patterns on a STM32G474RET6 board (
MotorBoard.elfflashed via onboardSTLINK-V3MODS, observingLED3 DEBUGwired directly toPC1) with200 msON/OFF pulse intervals and a1500 mspause between pattern repetitions:LedFault_HardFault): Forced an unaligned multi-word store (stmia) before enablingSCB->SHCSRfault handlers (USGFAULTENA = 0), escalating toHardFault_Handlerand confirming a repeating 1-blink pattern.LedFault_StackOverflow): Overwrote a FreeRTOS task's stack sentinel buffer insideapp_main()and yielded (vTaskDelay(1)), triggeringvApplicationStackOverflowHookand confirming a repeating 2-blink pattern.LedFault_MallocFailed): CalledpvPortMalloc(SIZE_MAX)afterstartup_init(), triggeringvApplicationMallocFailedHookand confirming a repeating 3-blink pattern.LedFault_MemManage): Executed a function pointer in Execute-Never (XN) system space (((void (*)(void))0xE0000001)()), triggering an instruction access violation (IACCVIOL) inMemManage_Handlerand confirming a repeating 4-blink pattern.LedFault_BusFault): Read from unmapped memory (*(volatile uint32_t *)0xFFF00000) withBUSFAULTENAenabled, triggeringBusFault_Handlerand confirming a repeating 5-blink pattern.LedFault_UsageFault): EnabledSCB_CCR_UNALIGN_TRP_Mskand executed an unaligned 32-bit write (*(volatile uint32_t *)0x20000001 = 0xDEADBEEF), triggeringUsageFault_Handlerand confirming a repeating 6-blink pattern.LedFault_NMI): SetSCB->ICSR = SCB_ICSR_NMIPENDSET_Mskto pend a Non-Maskable Interrupt, triggeringNMI_Handlerand confirming a repeating 7-blink pattern.LedFault_RTOSAssert): TriggeredconfigASSERT(0), routing intoLedFault_halt(LedFault_RTOSAssert)and confirming a repeating 9-blink pattern.Related Issue
Related to #204
Notes