We have a hard fault in our app that is pretty hard to reproduce and it takes a fair bit of time to do. I would like to be able to get more data about the crash other than the register dump printed on the console at the time of the crash. The dump is:
++ MbedOS Fault Handler ++ FaultType: HardFault Context: R0 : E04FF020 R1 : 10002B00 R2 : 00000000 R3 : 00000471 R4 : 2008078C R5 : 20080178 R6 : 00000000 R7 : 10005E70 R8 : 000027CA R9 : 34A3F045 R10 : 20080790 R11 : 00000000 R12 : 00044E45 SP : 100044D0 LR : 0003A7E7 PC : 0003A96A xPSR : 21000000 PSP : 100044B0 MSP : 10007FA0 CPUID: 412FC230 HFSR : 40000000 MMFSR: 00000082 BFSR : 00000000 UFSR : 00000000 DFSR : 00000000 AFSR : 00000000 MMFAR: 00000000 Mode : Thread Priv : Privileged Stack: PSP -- MbedOS Fault Handler --
Based on data I have found for this dump it seems that MMFSR
tells me;
DACCVIOL
- Indicates that a data access triggered the MemManage fault.MMARVALID
- Indicates that the MemManage Fault Address Register (MMFAR
), a 32 bit register located at0xE000ED34
, holds the address which triggered the MemManage fault.
Also HFSR
seems to tell me:
DEBUGEVT
- Indicates that a debug event (i.e executing a breakpoint instruction) occurred while the debug subsystem was not enabled
But all these really tell me nothing more than that I apparently read data from a NULL pointer, as MMFAR
is 0. So, to get more info I wanted to save the crash data and decode it during the next boot. For that I enabled the crash handling:
"target_overrides": {
"*": {
"platform.crash-capture-enabled": true,
"platform.error-hist-enabled": true,
"platform.fatal-error-auto-reboot-enabled": true,
That gave a linker error for the missing crash data region, so I added:
.crash_data_ram :
{
. = ALIGN(8);
__CRASH_DATA_RAM__ = .;
__CRASH_DATA_RAM_START__ = .; /* Create a global symbol at data start */
KEEP(*(.keep.crash_data_ram))
*(.m_crash_data_ram) /* This is a user defined section */
. += M_CRASH_DATA_RAM_SIZE;
. = ALIGN(8);
__CRASH_DATA_RAM_END__ = .; /* Define a global symbol at data end */
} > RAM
to targets/TARGET_NXP/TARGET_LPC176X/device/TOOLCHAIN_GCC_ARM/LPC1768.ld
right before the .data
segment and my app links and runs just fine. To decode the crash data I added this snippet to my main file:
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
mbed_error_ctx error_ctx;
mbed_error_status_t err_status;
mbed_fault_context_t fault_ctx;
static int reboot_error_happened = 0;
void mbed_error_reboot_callback(mbed_error_ctx *error_context) {
printf("mbed_error_reboot_callback: System rebooting, reboot error callback received");
reboot_error_happened = 1;
err_status = error_context->error_status;
mbed_get_reboot_error_info(&error_ctx);
mbed_reset_reboot_error_info();
}
void printErrorReport() {
if (err_status < 0) {
log("\nSuccessfully read reboot info ==> \n");
log("\n error status: 0x%08lX", (uint32_t)error_ctx.error_status);
log("\n error value: 0x%08lX", (uint32_t)error_ctx.error_value);
log("\n error address: 0x%08lX", (uint32_t)error_ctx.error_address);
log("\n error reboot count: 0x%08lX", (uint32_t)error_ctx.error_reboot_count);
log("\n error crc: 0x%08lX\n", (uint32_t)error_ctx.crc_error_ctx);
//Read fault context
if(error_ctx.error_status == MBED_ERROR_HARDFAULT_EXCEPTION) {
mbed_get_reboot_fault_context(&fault_ctx);
log("\nCrash Report data captured:\n");
for(int i=0;i<16;i++) {
log("[%d]: 0x%08X\n", i, ((uint32_t *)(&fault_ctx))[i]);
}
}
}
}
#endif
This is mostly straight from the docs. In main()
I check the error state as soon as I’ve enabled the console for logging:
#if MBED_CONF_PLATFORM_CRASH_CAPTURE_ENABLED
log("main: error state: %d", reboot_error_happened);
// any errors?
if ( reboot_error_happened == 0) {
printErrorReport();
}
#endif
To test I trigger a hard fault after a minute of running the app using the same code as in the docs:
void generateCrash() {
SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk;
uint32_t inv_addr = 0xAAA3;
uint32_t val = *(uint32_t *)inv_addr;
printf("\nval= %X", val);
return;
}
However, I never seem to get any crash data. My mbed_error_reboot_callback
is never called. So something in my setup is wrong, or this hardware simply can not handle storing crash reports. My guess is that the memory segment gets erased during the boot, but that’s just a somewhat uneducated guess. Googling for this only turns up millions of posts with regular crashes, not much about getting info about them.