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 { struct FaultStatusRegisters {
uint32_t HFSR; uint32_t HFSR;
uint32_t CFSR; uint32_t CFSR;
uint32_t MMFAR;
uint32_t BFAR; uint32_t BFAR;
uint32_t DFSR; uint32_t DFSR;
uint32_t AFSR; uint32_t AFSR;
uint32_t SHCSR; uint32_t SHCSR;
}; };
enum class FaultType {
HardFault, MemManage, BusFault, UsageFault
};
struct FlashDump {
FaultType type;
uint32_t stacked_registers[8];
FaultStatusRegisters fsr;
};
struct FlashDumpInfo { struct FlashDumpInfo {
uint8_t _zero; // Used to check that the storage area has been initialized uint8_t _zero; // Used to check that the storage area has been initialized
uint32_t n_dumps; 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_BASE = 0;
constexpr uint32_t FLASH_DUMP_ADDR_INFO = FLASH_DUMP_ADDR_BASE + 0; constexpr uint32_t FLASH_DUMP_ADDR_INFO = FLASH_DUMP_ADDR_BASE + 0;
constexpr uint32_t FLASH_DUMP_ADDR_DUMPS = constexpr uint32_t FLASH_DUMP_ADDR_DUMPS =
FLASH_DUMP_ADDR_INFO + sizeof(FlashDump); 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); const FaultStatusRegisters *fsr);
/** /**
* Read the FlashDumpInfo (and create it if it hasn't been initialized yet). * 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 FlashDumpInfo *flash_dump_get_info();
const FlashDump *flash_dump_get_fault(uint32_t n); 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_dumped_faults(bool in_irq=false);
void print_stacked_registers(const uint32_t *stack); void print_stacked_registers(const uint32_t *stack, bool in_irq=false);
void print_fault_registers(const FaultStatusRegisters *fsr); void print_fault_registers(const FaultStatusRegisters *fsr, bool in_irq=false);
FaultStatusRegisters get_current_fsr(); 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); 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; 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; FlashDumpInfo info;
memcpy(&info, flash_dump_get_info(), sizeof(info)); memcpy(&info, flash_dump_get_info(), sizeof(info));
FlashDump dump; FlashDump dump;
dump.type = fault_type;
memcpy(dump.stacked_registers, stack, sizeof(dump.stacked_registers)); memcpy(dump.stacked_registers, stack, sizeof(dump.stacked_registers));
memcpy(&dump.fsr, fsr, sizeof(dump.fsr)); 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); return (const FlashDump *)Flash.readAddress(addr);
} }
bool check_serial_available() { void uart_wait_for_txrdy() {
int available = Serial.availableForWrite(); while ((UART->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
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() { 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');
}
}
return 8;
}
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; uint32_t n = flash_dump_get_info()->n_dumps;
Serial.println("===================="); print("====================\n", in_irq);
Serial.print(n); print_hex(n, in_irq);
Serial.println(" DUMPED FAULTS"); print(" DUMPED FAULTS\n", in_irq);
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
Serial.println("--------------------"); print("--------------------\n", in_irq);
Serial.print("Fault "); print("Fault ", in_irq);
Serial.println(i); print_hex(i, in_irq);
write('\n', in_irq);
const FlashDump *dump = flash_dump_get_fault(i); const FlashDump *dump = flash_dump_get_fault(i);
print_stacked_registers(dump->stacked_registers); print(get_fault_type_name(dump->type), in_irq);
print_fault_registers(&dump->fsr); 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) { void print_stacked_registers(const uint32_t *stack, bool in_irq) {
Serial.print("R0 = "); print("R0 = ", in_irq);
Serial.println(stack[0], HEX); print_hex(stack[0], in_irq);
Serial.print("R1 = "); write('\n', in_irq);
Serial.println(stack[1], HEX); print("R1 = ", in_irq);
Serial.print("R2 = "); print_hex(stack[1], in_irq);
Serial.println(stack[2], HEX); write('\n', in_irq);
Serial.print("R3 = "); print("R2 = ", in_irq);
Serial.println(stack[3], HEX); print_hex(stack[2], in_irq);
Serial.print("R12 = "); write('\n', in_irq);
Serial.println(stack[4], HEX); print("R3 = ", in_irq);
Serial.print("LR = "); print_hex(stack[3], in_irq);
Serial.println(stack[5], HEX); write('\n', in_irq);
Serial.print("PC = "); print("R12 = ", in_irq);
Serial.println(stack[6], HEX); print_hex(stack[4], in_irq);
Serial.print("PSR = "); write('\n', in_irq);
Serial.println(stack[7], HEX); print("LR = ", in_irq);
Serial.println(); 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) { void print_fault_registers(const FaultStatusRegisters *fsr, bool in_irq) {
Serial.print("HFSR = "); print("HFSR = ", in_irq);
Serial.println(fsr->HFSR, HEX); print_hex(fsr->HFSR, in_irq);
Serial.print("CFSR = "); write('\n', in_irq);
Serial.println(fsr->CFSR, HEX); print("CFSR = ", in_irq);
Serial.print("BFAR = "); print_hex(fsr->CFSR, in_irq);
Serial.println(fsr->BFAR, HEX); write('\n', in_irq);
Serial.print("DFSR = "); print("MMFAR = ", in_irq);
Serial.println(fsr->DFSR, HEX); print_hex(fsr->MMFAR, in_irq);
Serial.print("AFSR = "); write('\n', in_irq);
Serial.println(fsr->AFSR, HEX); print("BFAR = ", in_irq);
Serial.print("SHCSR = "); print_hex(fsr->BFAR, in_irq);
Serial.println(fsr->SHCSR, HEX); write('\n', in_irq);
Serial.println();
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 get_current_fsr() {
FaultStatusRegisters fsr; FaultStatusRegisters fsr;
fsr.HFSR = SCB->HFSR; fsr.HFSR = SCB->HFSR;
fsr.CFSR = SCB->CFSR; fsr.CFSR = SCB->CFSR;
fsr.MMFAR = SCB->MMFAR;
fsr.BFAR = SCB->BFAR; fsr.BFAR = SCB->BFAR;
fsr.DFSR = SCB->DFSR; fsr.DFSR = SCB->DFSR;
fsr.AFSR = SCB->AFSR; fsr.AFSR = SCB->AFSR;
fsr.SHCSR = SCB->SHCSR; fsr.SHCSR = SCB->SHCSR;
return fsr; return fsr;
} }
void fault_handler(uint32_t *stack_addr, const char *fault_type, const char *get_fault_type_name(FaultType type) {
const int *leds, unsigned n_leds) { 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); Serial.begin(9600);
for (unsigned i = 0; i < n_leds; i++) { for (unsigned i = 0; i < n_leds; i++) {
pinMode(leds[i], OUTPUT); pinMode(leds[i], OUTPUT);
@ -129,25 +203,23 @@ void fault_handler(uint32_t *stack_addr, const char *fault_type,
FaultStatusRegisters fsr = get_current_fsr(); FaultStatusRegisters fsr = get_current_fsr();
flash_dump_fault(stack_addr, &fsr); flash_dump_write_fault(fault_type, stack_addr, &fsr);
while (1) { while (1) {
if (check_serial_available()) { uart_print("====================\n");
Serial.println("===================="); uart_print(get_fault_type_name(fault_type));
Serial.println(fault_type); uart_print("\n====================\n");
Serial.println("====================");
print_stacked_registers(stack_addr); print_stacked_registers(stack_addr, true);
print_fault_registers(&fsr); print_fault_registers(&fsr, true);
}
for (unsigned i = 0; i < n_leds; i++) { for (unsigned i = 0; i < n_leds; i++) {
digitalWrite(leds[i], HIGH); digitalWrite(leds[i], HIGH);
} }
delay(500); busy_wait(5000000);
for (unsigned i = 0; i < n_leds; i++) { for (unsigned i = 0; i < n_leds; i++) {
digitalWrite(leds[i], LOW); 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) { void HardFault_Handler_C(uint32_t *stack_addr) {
// All LEDs // All LEDs except for the bottom ones
static const int leds[] = {led1, led2, led3, led4, led5, led6, static const int leds[] = {led1, led2, led3, led4, led5, led6, led7,
led7, led8, led9, led10, led11, led12, led8, led9, led10, led11, led12, led14, led15};
led13, led14, led15, led16}; fault_handler(stack_addr, FaultType::HardFault, leds,
fault_handler(stack_addr, "HARD FAULT", leds, sizeof(leds) / sizeof(int)); sizeof(leds) / sizeof(int));
} }
void MemManage_Handler_C(uint32_t *stack_addr) { void MemManage_Handler_C(uint32_t *stack_addr) {
// Left of display // Left of display
static const int leds[] = {led11, led12, led13}; 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)); sizeof(leds) / sizeof(int));
} }
void BusFault_Handler_C(uint32_t *stack_addr) { void BusFault_Handler_C(uint32_t *stack_addr) {
// Right of display // Right of display
static const int leds[] = {led14, led15, led16}; 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) { void UsageFault_Handler_C(uint32_t *stack_addr) {
// Left and right of display // Left and right of display
static const int leds[] = {led11, led12, led13, led14, led15, led16}; 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));
} }
} }