mirror of
https://github.com/meshtastic/firmware.git
synced 2026-04-03 23:13:08 -04:00
Add a hardfault handler so it's more obvious when STM32 crashes. (#10071)
* Add hardfault handler so it's more obvious when STM32 crashes. * thanks copilot
This commit is contained in:
11
src/platform/stm32wl/hardfault_handler.s
Normal file
11
src/platform/stm32wl/hardfault_handler.s
Normal file
@@ -0,0 +1,11 @@
|
||||
.globl HardFault_Handler
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
tst lr, #4
|
||||
ite eq
|
||||
mrseq r0, msp
|
||||
mrsne r0, psp
|
||||
b HardFault_Handler_C
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include <stdarg.h>
|
||||
#include <stm32wle5xx.h>
|
||||
#include <stm32wlxx_hal.h>
|
||||
|
||||
@@ -53,4 +54,99 @@ extern "C" void __wrap__tzset_unlocked_r(struct _reent *reent_ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Taken from https://interrupt.memfault.com/blog/cortex-m-hardfault-debug
|
||||
typedef struct __attribute__((packed)) ContextStateFrame {
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
uint32_t r2;
|
||||
uint32_t r3;
|
||||
uint32_t r12;
|
||||
uint32_t lr;
|
||||
uint32_t return_address;
|
||||
uint32_t xpsr;
|
||||
} sContextStateFrame;
|
||||
|
||||
// NOTE: If you are using CMSIS, the registers can also be
|
||||
// accessed through CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk
|
||||
#define HALT_IF_DEBUGGING() \
|
||||
do { \
|
||||
if ((*(volatile uint32_t *)0xE000EDF0) & (1 << 0)) { \
|
||||
__asm("bkpt 1"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char hardfault_message_buffer[256];
|
||||
|
||||
// printf directly using srcwrapper's debug UART function.
|
||||
static void debug_printf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int length = vsnprintf(hardfault_message_buffer, sizeof(hardfault_message_buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
if (length < 0)
|
||||
return;
|
||||
uart_debug_write((uint8_t *)hardfault_message_buffer, min((unsigned int)length, sizeof(hardfault_message_buffer) - 1));
|
||||
}
|
||||
|
||||
// N picked by guessing
|
||||
#define DOT_TIME 1200000
|
||||
static void dot()
|
||||
{
|
||||
digitalWrite(LED_POWER, LED_STATE_ON);
|
||||
for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */
|
||||
}
|
||||
digitalWrite(LED_POWER, LED_STATE_OFF);
|
||||
for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
static void dash()
|
||||
{
|
||||
digitalWrite(LED_POWER, LED_STATE_ON);
|
||||
for (volatile int i = 0; i < (DOT_TIME * 3); i++) { /* busy wait */
|
||||
}
|
||||
digitalWrite(LED_POWER, LED_STATE_OFF);
|
||||
for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
static void space()
|
||||
{
|
||||
for (volatile int i = 0; i < (DOT_TIME * 3); i++) { /* busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
// Disable optimizations for this function so "frame" argument
|
||||
// does not get optimized away
|
||||
extern "C" __attribute__((optimize("O0"))) void HardFault_Handler_C(sContextStateFrame *frame)
|
||||
{
|
||||
debug_printf("HardFault!\r\n");
|
||||
debug_printf("r0: %08x\r\n", frame->r0);
|
||||
debug_printf("r1: %08x\r\n", frame->r1);
|
||||
debug_printf("r2: %08x\r\n", frame->r2);
|
||||
debug_printf("r3: %08x\r\n", frame->r3);
|
||||
debug_printf("r12: %08x\r\n", frame->r12);
|
||||
debug_printf("lr: %08x\r\n", frame->lr);
|
||||
debug_printf("pc[return address]: %08x\r\n", frame->return_address);
|
||||
debug_printf("xpsr: %08x\r\n", frame->xpsr);
|
||||
|
||||
HALT_IF_DEBUGGING();
|
||||
|
||||
// blink SOS forever
|
||||
while (1) {
|
||||
dot();
|
||||
dot();
|
||||
dot();
|
||||
dash();
|
||||
dash();
|
||||
dash();
|
||||
dot();
|
||||
dot();
|
||||
dot();
|
||||
space();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user