Add fault handlers for debugging

The fault handlers blink different LEDs depending on the kind of fault:

HardFault  -> All
MemManage  -> Left of display
BusFault   -> Right of display
UsageFault -> Left and right of display

Additionally, they dump information about the fault to the flash and
Serial (if connected). The information dumped to the flash can later be
retrieved via Serial by sending a 'd'.
This commit is contained in:
jazzpi
2021-07-17 20:11:55 +02:00
parent 7815f03c84
commit 2ca1ec4b8f
4 changed files with 274 additions and 1 deletions

View File

@ -8,9 +8,11 @@
#include <RotaryEncoder.h>
#include <due_can.h>
#include "debug.h"
void setup() {
set_pins();
// Serial.begin(9600);
Serial.begin(9600);
// Serial.println("Hi");
Init_Can_0();
init_display();
@ -22,4 +24,8 @@ void loop() {
// Send_0x110(); //alle 10 ms als interrupt aufgerufen
update_LED();
update_display();
if (Serial.available() > 0 && Serial.read() == 'd') {
print_dumped_faults();
}
}

220
src/debug.cpp Normal file
View File

@ -0,0 +1,220 @@
#include "debug.h"
#include "FT18_STW_INIT.h"
#include <DueFlashStorage.h>
DueFlashStorage Flash;
void flash_dump_fault(const uint32_t *stack, const FaultStatusRegisters *fsr) {
FlashDumpInfo info;
memcpy(&info, flash_dump_get_info(), sizeof(info));
FlashDump dump;
memcpy(dump.stacked_registers, stack, sizeof(dump.stacked_registers));
memcpy(&dump.fsr, fsr, sizeof(dump.fsr));
uint32_t new_addr = FLASH_DUMP_ADDR_DUMPS + info.n_dumps * sizeof(dump);
Flash.write(new_addr, (uint8_t *)&dump, sizeof(dump));
info.n_dumps++;
Flash.write(FLASH_DUMP_ADDR_INFO, (uint8_t *)&info, sizeof(info));
}
const FlashDumpInfo *flash_dump_get_info() {
if (Flash.read(FLASH_DUMP_ADDR_INFO) != 0) {
FlashDumpInfo info;
info._zero = 0;
info.n_dumps = 0;
Flash.write(FLASH_DUMP_ADDR_INFO, (uint8_t *)&info, sizeof(info));
}
return (const FlashDumpInfo *)Flash.readAddress(FLASH_DUMP_ADDR_INFO);
}
const FlashDump *flash_dump_get_fault(uint32_t n) {
uint32_t addr = FLASH_DUMP_ADDR_DUMPS + n * sizeof(FlashDump);
return (const FlashDump *)Flash.readAddress(addr);
}
bool check_serial_available() {
int available = Serial.availableForWrite();
if (available == 0) {
// No bytes available for write, maybe we were just writing? Wait 10 ms and
// check again.
delay(10);
available = Serial.availableForWrite();
if (available == 0) {
// Still no bytes available for write, looks like we can't write at all.
return false;
}
}
// Write a byte, and wait 10 ms. If the number of available bytes decreased,
// we can't write.
Serial.write('\0');
delay(10);
return Serial.availableForWrite() >= available;
}
void print_dumped_faults() {
uint32_t n = flash_dump_get_info()->n_dumps;
Serial.println("====================");
Serial.print(n);
Serial.println(" DUMPED FAULTS");
for (uint32_t i = 0; i < n; i++) {
Serial.println("--------------------");
Serial.print("Fault ");
Serial.println(i);
const FlashDump *dump = flash_dump_get_fault(i);
print_stacked_registers(dump->stacked_registers);
print_fault_registers(&dump->fsr);
}
Serial.println("====================");
}
void print_stacked_registers(const uint32_t *stack) {
Serial.print("R0 = ");
Serial.println(stack[0], HEX);
Serial.print("R1 = ");
Serial.println(stack[1], HEX);
Serial.print("R2 = ");
Serial.println(stack[2], HEX);
Serial.print("R3 = ");
Serial.println(stack[3], HEX);
Serial.print("R12 = ");
Serial.println(stack[4], HEX);
Serial.print("LR = ");
Serial.println(stack[5], HEX);
Serial.print("PC = ");
Serial.println(stack[6], HEX);
Serial.print("PSR = ");
Serial.println(stack[7], HEX);
Serial.println();
}
void print_fault_registers(const FaultStatusRegisters *fsr) {
Serial.print("HFSR = ");
Serial.println(fsr->HFSR, HEX);
Serial.print("CFSR = ");
Serial.println(fsr->CFSR, HEX);
Serial.print("BFAR = ");
Serial.println(fsr->BFAR, HEX);
Serial.print("DFSR = ");
Serial.println(fsr->DFSR, HEX);
Serial.print("AFSR = ");
Serial.println(fsr->AFSR, HEX);
Serial.print("SHCSR = ");
Serial.println(fsr->SHCSR, HEX);
Serial.println();
}
FaultStatusRegisters get_current_fsr() {
FaultStatusRegisters fsr;
fsr.HFSR = SCB->HFSR;
fsr.CFSR = SCB->CFSR;
fsr.BFAR = SCB->BFAR;
fsr.DFSR = SCB->DFSR;
fsr.AFSR = SCB->AFSR;
fsr.SHCSR = SCB->SHCSR;
return fsr;
}
void fault_handler(uint32_t *stack_addr, const char *fault_type,
const int *leds, unsigned n_leds) {
Serial.begin(9600);
for (unsigned i = 0; i < n_leds; i++) {
pinMode(leds[i], OUTPUT);
}
FaultStatusRegisters fsr = get_current_fsr();
flash_dump_fault(stack_addr, &fsr);
while (1) {
if (check_serial_available()) {
Serial.println("====================");
Serial.println(fault_type);
Serial.println("====================");
print_stacked_registers(stack_addr);
print_fault_registers(&fsr);
}
for (unsigned i = 0; i < n_leds; i++) {
digitalWrite(leds[i], HIGH);
}
delay(500);
for (unsigned i = 0; i < n_leds; i++) {
digitalWrite(leds[i], LOW);
}
delay(500);
}
}
// If we don't wrap the handler functions in an extern C block, their names get
// mangled and they won't override the weakly-linked handler functions defined
// in the Arduino(-SAM) framework.
extern "C" {
// Get the stack pointer and pass it to the respective C handler. Depending on
// the EXC_RETURN value, we need to either use the Main Stack Pointer (msp) or
// the Process Stack Pointer (psp).
void HardFault_Handler(void) {
__ASM("tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b HardFault_Handler_C");
}
void MemManage_Handler(void) {
__ASM("tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b MemManage_Handler_C");
}
void BusFault_Handler(void) {
__ASM("tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b BusFault_Handler_C");
}
void UsageFault_Handler(void) {
__ASM("tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b UsageFault_Handler_C");
}
void HardFault_Handler_C(uint32_t *stack_addr) {
// All LEDs
static const int leds[] = {led1, led2, led3, led4, led5, led6,
led7, led8, led9, led10, led11, led12,
led13, led14, led15, led16};
fault_handler(stack_addr, "HARD FAULT", leds, sizeof(leds) / sizeof(int));
}
void MemManage_Handler_C(uint32_t *stack_addr) {
// Left of display
static const int leds[] = {led11, led12, led13};
fault_handler(stack_addr, "MEMMANAGE FAULT", leds,
sizeof(leds) / sizeof(int));
}
void BusFault_Handler_C(uint32_t *stack_addr) {
// Right of display
static const int leds[] = {led14, led15, led16};
fault_handler(stack_addr, "BUS FAULT", leds, sizeof(leds) / sizeof(int));
}
void UsageFault_Handler_C(uint32_t *stack_addr) {
// Left and right of display
static const int leds[] = {led11, led12, led13, led14, led15, led16};
fault_handler(stack_addr, "USAGE FAULT", leds, sizeof(leds) / sizeof(int));
}
}