Bugfixes for fault handlers

This commit is contained in:
jvblanck 2021-07-18 17:14:03 +02:00
parent 2ca1ec4b8f
commit fb68e8c4d6
2 changed files with 181 additions and 89 deletions

View File

@ -5,28 +5,35 @@
struct FaultStatusRegisters {
uint32_t HFSR;
uint32_t CFSR;
uint32_t MMFAR;
uint32_t BFAR;
uint32_t DFSR;
uint32_t AFSR;
uint32_t SHCSR;
};
enum class FaultType {
HardFault, MemManage, BusFault, UsageFault
};
struct FlashDump {
FaultType type;
uint32_t stacked_registers[8];
FaultStatusRegisters fsr;
};
struct FlashDumpInfo {
uint8_t _zero; // Used to check that the storage area has been initialized
uint32_t n_dumps;
};
struct FlashDump {
uint32_t stacked_registers[8];
FaultStatusRegisters fsr;
};
constexpr uint32_t FLASH_DUMP_ADDR_BASE = 0;
constexpr uint32_t FLASH_DUMP_ADDR_INFO = FLASH_DUMP_ADDR_BASE + 0;
constexpr uint32_t FLASH_DUMP_ADDR_DUMPS =
FLASH_DUMP_ADDR_INFO + sizeof(FlashDump);
void flash_dump_write_fault(const uint32_t *stack,
void flash_dump_write_fault(FaultType fault_type, const uint32_t *stack,
const FaultStatusRegisters *fsr);
/**
* Read the FlashDumpInfo (and create it if it hasn't been initialized yet).
@ -34,13 +41,24 @@ void flash_dump_write_fault(const uint32_t *stack,
const FlashDumpInfo *flash_dump_get_info();
const FlashDump *flash_dump_get_fault(uint32_t n);
bool check_serial_available();
void uart_wait_for_txrdy();
size_t uart_write(uint8_t c);
size_t uart_print(const char* str);
size_t uart_print_hex(uint32_t x);
void print_dumped_faults();
void print_stacked_registers(const uint32_t *stack);
void print_fault_registers(const FaultStatusRegisters *fsr);
void print_dumped_faults(bool in_irq=false);
void print_stacked_registers(const uint32_t *stack, bool in_irq=false);
void print_fault_registers(const FaultStatusRegisters *fsr, bool in_irq=false);
FaultStatusRegisters get_current_fsr();
void fault_handler(uint32_t *stack_addr, const char *fault_type,
const char* get_fault_type_name(FaultType type);
void fault_handler(uint32_t *stack_addr, FaultType fault_type,
const int *leds, unsigned n_leds);
void inline busy_wait(size_t iterations) {
for (size_t i = 0; i < iterations; i++) {
// Does nothing, but ensures the compiler doesn't optimize the loop away.
__ASM ("" ::: "memory");
}
}

View File

@ -6,11 +6,13 @@
DueFlashStorage Flash;
void flash_dump_fault(const uint32_t *stack, const FaultStatusRegisters *fsr) {
void flash_dump_write_fault(FaultType fault_type, const uint32_t *stack,
const FaultStatusRegisters *fsr) {
FlashDumpInfo info;
memcpy(&info, flash_dump_get_info(), sizeof(info));
FlashDump dump;
dump.type = fault_type;
memcpy(dump.stacked_registers, stack, sizeof(dump.stacked_registers));
memcpy(&dump.fsr, fsr, sizeof(dump.fsr));
@ -36,92 +38,164 @@ const FlashDump *flash_dump_get_fault(uint32_t n) {
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;
void uart_wait_for_txrdy() {
while ((UART->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
;
}
size_t uart_write(uint8_t c) {
uart_wait_for_txrdy();
UART->UART_THR = c;
uart_wait_for_txrdy();
return 1;
}
size_t uart_print(const char *str) {
const char *c = str;
while (*c != '\0') {
uart_write(*c);
c++;
}
return c - str;
}
size_t uart_print_hex(uint32_t x) {
for (int i = 0; i < 8; i++) {
uint8_t nibble = (x >> (7 - i) * 4) & 0xF;
if (nibble < 0xA) {
uart_write(nibble + '0');
} else {
uart_write(nibble - 0xA + 'A');
}
}
// 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;
return 8;
}
void print_dumped_faults() {
size_t write(uint8_t c, bool in_irq) {
if (in_irq) {
uart_write(c);
} else {
Serial.write(c);
}
}
size_t print(const char *str, bool in_irq) {
if (in_irq) {
uart_print(str);
} else {
Serial.print(str);
}
}
size_t print_hex(uint32_t x, bool in_irq) {
if (in_irq) {
uart_print_hex(x);
} else {
Serial.print(x, HEX);
}
}
void print_dumped_faults(bool in_irq) {
uint32_t n = flash_dump_get_info()->n_dumps;
Serial.println("====================");
Serial.print(n);
Serial.println(" DUMPED FAULTS");
print("====================\n", in_irq);
print_hex(n, in_irq);
print(" DUMPED FAULTS\n", in_irq);
for (uint32_t i = 0; i < n; i++) {
Serial.println("--------------------");
Serial.print("Fault ");
Serial.println(i);
print("--------------------\n", in_irq);
print("Fault ", in_irq);
print_hex(i, in_irq);
write('\n', in_irq);
const FlashDump *dump = flash_dump_get_fault(i);
print_stacked_registers(dump->stacked_registers);
print_fault_registers(&dump->fsr);
print(get_fault_type_name(dump->type), in_irq);
write('\n', in_irq);
print_stacked_registers(dump->stacked_registers, in_irq);
print_fault_registers(&dump->fsr, in_irq);
}
Serial.println("====================");
print("====================\n", in_irq);
}
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_stacked_registers(const uint32_t *stack, bool in_irq) {
print("R0 = ", in_irq);
print_hex(stack[0], in_irq);
write('\n', in_irq);
print("R1 = ", in_irq);
print_hex(stack[1], in_irq);
write('\n', in_irq);
print("R2 = ", in_irq);
print_hex(stack[2], in_irq);
write('\n', in_irq);
print("R3 = ", in_irq);
print_hex(stack[3], in_irq);
write('\n', in_irq);
print("R12 = ", in_irq);
print_hex(stack[4], in_irq);
write('\n', in_irq);
print("LR = ", in_irq);
print_hex(stack[5], in_irq);
write('\n', in_irq);
print("PC = ", in_irq);
print_hex(stack[6], in_irq);
write('\n', in_irq);
print("PSR = ", in_irq);
print_hex(stack[7], in_irq);
write('\n', in_irq);
write('\n', in_irq);
}
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();
void print_fault_registers(const FaultStatusRegisters *fsr, bool in_irq) {
print("HFSR = ", in_irq);
print_hex(fsr->HFSR, in_irq);
write('\n', in_irq);
print("CFSR = ", in_irq);
print_hex(fsr->CFSR, in_irq);
write('\n', in_irq);
print("MMFAR = ", in_irq);
print_hex(fsr->MMFAR, in_irq);
write('\n', in_irq);
print("BFAR = ", in_irq);
print_hex(fsr->BFAR, in_irq);
write('\n', in_irq);
print("DFSR = ", in_irq);
print_hex(fsr->DFSR, in_irq);
write('\n', in_irq);
print("AFSR = ", in_irq);
print_hex(fsr->AFSR, in_irq);
write('\n', in_irq);
print("SHCSR = ", in_irq);
print_hex(fsr->SHCSR, in_irq);
write('\n', in_irq);
write('\n', in_irq);
}
FaultStatusRegisters get_current_fsr() {
FaultStatusRegisters fsr;
fsr.HFSR = SCB->HFSR;
fsr.CFSR = SCB->CFSR;
fsr.MMFAR = SCB->MMFAR;
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) {
const char *get_fault_type_name(FaultType type) {
switch (type) {
case FaultType::HardFault:
return "HARD FAULT";
case FaultType::MemManage:
return "MEMMANGAGE FAULT";
case FaultType::BusFault:
return "BUS FAULT";
case FaultType::UsageFault:
return "USAGE FAULT";
}
}
void fault_handler(uint32_t *stack_addr, FaultType fault_type, const int *leds,
unsigned n_leds) {
Serial.begin(9600);
for (unsigned i = 0; i < n_leds; i++) {
pinMode(leds[i], OUTPUT);
@ -129,25 +203,23 @@ void fault_handler(uint32_t *stack_addr, const char *fault_type,
FaultStatusRegisters fsr = get_current_fsr();
flash_dump_fault(stack_addr, &fsr);
flash_dump_write_fault(fault_type, stack_addr, &fsr);
while (1) {
if (check_serial_available()) {
Serial.println("====================");
Serial.println(fault_type);
Serial.println("====================");
uart_print("====================\n");
uart_print(get_fault_type_name(fault_type));
uart_print("\n====================\n");
print_stacked_registers(stack_addr);
print_fault_registers(&fsr);
}
print_stacked_registers(stack_addr, true);
print_fault_registers(&fsr, true);
for (unsigned i = 0; i < n_leds; i++) {
digitalWrite(leds[i], HIGH);
}
delay(500);
busy_wait(5000000);
for (unsigned i = 0; i < n_leds; i++) {
digitalWrite(leds[i], LOW);
}
delay(500);
busy_wait(5000000);
}
}
@ -192,29 +264,31 @@ void UsageFault_Handler(void) {
}
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));
// All LEDs except for the bottom ones
static const int leds[] = {led1, led2, led3, led4, led5, led6, led7,
led8, led9, led10, led11, led12, led14, led15};
fault_handler(stack_addr, FaultType::HardFault, 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,
fault_handler(stack_addr, FaultType::MemManage, 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));
fault_handler(stack_addr, FaultType::BusFault, 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));
fault_handler(stack_addr, FaultType::UsageFault, leds,
sizeof(leds) / sizeof(int));
}
}