4#ifdef USE_RP2040_CRASH_HANDLER
10#include <hardware/regs/addressmap.h>
11#include <hardware/structs/watchdog.h>
12#include <hardware/watchdog.h>
23static constexpr uint32_t CRASH_MAGIC_SENTINEL = 0xDEAD0000;
24static constexpr uint32_t CRASH_DATA_VERSION = 1;
25static constexpr uint32_t CRASH_MAGIC_V1 = CRASH_MAGIC_SENTINEL | CRASH_DATA_VERSION;
41#if defined(PICO_RP2350)
42static constexpr uint32_t FLASH_SCAN_END = XIP_BASE + 0x400000;
44static constexpr uint32_t FLASH_SCAN_END = XIP_BASE + 0x200000;
49 return cleared >= XIP_BASE && cleared < FLASH_SCAN_END;
52static constexpr size_t MAX_BACKTRACE = 4;
56static const char *
const TAG =
"rp2040.crash";
60static struct CrashData {
66 uint8_t backtrace_count;
72 s_crash_data.valid =
false;
73 uint32_t magic = watchdog_hw->scratch[0];
74 if ((magic & 0xFFFF0000) == CRASH_MAGIC_SENTINEL && (magic & 0xFFFF) == CRASH_DATA_VERSION) {
75 s_crash_data.valid =
true;
76 s_crash_data.pc = watchdog_hw->scratch[1];
77 s_crash_data.lr = watchdog_hw->scratch[2];
78 s_crash_data.sp = watchdog_hw->scratch[3];
79 s_crash_data.backtrace_count = 0;
80 for (
size_t i = 0; i < MAX_BACKTRACE; i++) {
81 uint32_t addr = watchdog_hw->scratch[4 + i];
84 s_crash_data.backtrace[i] = addr;
85 s_crash_data.backtrace_count++;
89 for (
int i = 0; i < 8; i++) {
90 watchdog_hw->scratch[i] = 0;
100 if (!s_crash_data.valid)
103 ESP_LOGE(TAG,
"*** CRASH DETECTED ON PREVIOUS BOOT ***");
104 ESP_LOGE(TAG,
" PC: 0x%08" PRIX32
" (fault location)", s_crash_data.pc);
105 ESP_LOGE(TAG,
" LR: 0x%08" PRIX32
" (return address)", s_crash_data.lr);
106 ESP_LOGE(TAG,
" SP: 0x%08" PRIX32, s_crash_data.sp);
107 for (uint8_t i = 0; i < s_crash_data.backtrace_count; i++) {
108 ESP_LOGE(TAG,
" BT%d: 0x%08" PRIX32
" (stack backtrace)", i, s_crash_data.backtrace[i]);
112 int pos = snprintf(hint,
sizeof(hint),
"Use: addr2line -pfiaC -e firmware.elf 0x%08" PRIX32
" 0x%08" PRIX32,
113 s_crash_data.pc, s_crash_data.lr);
114 for (uint8_t i = 0; i < s_crash_data.backtrace_count &&
pos < (int)
sizeof(hint) - 12; i++) {
115 pos += snprintf(hint +
pos,
sizeof(hint) -
pos,
" 0x%08" PRIX32, s_crash_data.backtrace[i]);
117 ESP_LOGE(TAG,
"%s", hint);
133static inline bool is_valid_sram_ptr(
const uint32_t *ptr) {
134 auto addr =
reinterpret_cast<uintptr_t
>(ptr);
137 return (addr % 4 == 0) && addr >= SRAM_BASE && (addr + 32) <= SRAM_END;
144 watchdog_reboot(0, 0, 10);
149 if (!is_valid_sram_ptr(frame)) {
150 watchdog_hw->scratch[0] = CRASH_MAGIC_V1;
151 watchdog_hw->scratch[1] = 0;
152 watchdog_hw->scratch[2] = 0;
153 watchdog_hw->scratch[3] =
reinterpret_cast<uintptr_t
>(frame);
154 for (
uint32_t i = 0; i < MAX_BACKTRACE; i++) {
155 watchdog_hw->scratch[4 + i] = 0;
158 __asm
volatile(
"nop");
166 static constexpr uint32_t EF_XPSR = 7;
172 watchdog_hw->scratch[0] = CRASH_MAGIC_V1;
173 watchdog_hw->scratch[1] = frame[EF_PC];
174 watchdog_hw->scratch[2] = frame[EF_LR];
191 if (is_code_addr(
val) &&
val != frame[EF_PC] &&
val != frame[EF_LR]) {
198 watchdog_hw->scratch[4 + i] = 0;
202 __asm
volatile(
"nop");
221 __asm
volatile(
"movs r0, #4 \n"
236 :
"i"(hard_fault_handler_c));
struct @65::@66 __attribute__
void crash_handler_log()
Log crash data if a crash was detected on previous boot.
bool crash_handler_has_data()
Returns true if crash data was found this boot.
void crash_handler_read_and_clear()
Read crash data from watchdog scratch registers and clear them.