Bugfixes for fault handlers
This commit is contained in:
parent
2ca1ec4b8f
commit
fb68e8c4d6
@ -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");
|
||||||
|
}
|
||||||
|
}
|
234
src/debug.cpp
234
src/debug.cpp
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user