Show backtrace

This commit is contained in:
cpq
2026-09-15 14:20:15 +01:00
parent ed5ef09d1c
commit 29aa53cebd
3 changed files with 37 additions and 77 deletions
@@ -1,2 +1,11 @@
#pragma once
#define MG_ARCH MG_ARCH_CUBE
// Ethernet driver tunables:
// #define MG_DRIVER_MDC_CR 4 // RMII MDC clock divider, from 0 to 5
// #define MG_TCPIP_PHY_ADDR 0 // PHY address
// Uncomment this for static IP configuration:
// #define MG_TCPIP_IP MG_IPV4(192, 168, 0, 10) // IP
// #define MG_TCPIP_GW MG_IPV4(192, 168, 0, 1) // Gateway
// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) // Netmask
+19 -35
View File
@@ -45,8 +45,8 @@ __attribute__((used, noinline)) static void fault_c(uint32_t *sp) {
mg_health_record.backtrace[n++] = sp[5] & ~1U; // Stacked LR
for (uint32_t *p = sp + 8;
n < MG_HEALTH_BACKTRACE &&
(uintptr_t) p < (uintptr_t) sp + 4096U && // Bound the scan
(uintptr_t) p < (uintptr_t) &_estack; // Stay in RAM
(uintptr_t) p < (uintptr_t) sp + 4096U && // Bound the scan
(uintptr_t) p < (uintptr_t) &_estack; // Stay in RAM
p++) {
uint32_t v = *p;
if ((v & 1U) && v >= 0x08000000U && v < 0x08000000U + 1024U * 1024U) {
@@ -60,8 +60,8 @@ __attribute__((used, noinline)) static void fault_c(uint32_t *sp) {
// 0 = MSP, 1 = PSP. Load the faulting SP into r0 and hand it to fault_c()
__attribute__((naked)) void HardFault_Handler(void) {
__asm volatile(
"tst lr, #4\n\t" // Test EXC_RETURN bit 2
"ite eq\n\t" // If zero, use MSP; else PSP
"tst lr, #4\n\t" // Test EXC_RETURN bit 2
"ite eq\n\t" // If zero, use MSP; else PSP
"mrseq r0, msp\n\t"
"mrsne r0, psp\n\t"
"b fault_c\n\t");
@@ -85,43 +85,24 @@ bool mg_random(void *buf, size_t len) {
}
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/ota/update"), NULL)) {
mg_http_start_ota(c, hm, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
} else if (mg_match(hm->uri, mg_str("/api/ota/commit"), NULL)) {
c->data[0] = 1;
mg_http_reply(c, 200, "", "ok\n");
} else if (mg_match(hm->uri, mg_str("/api/ota/rollback"), NULL)) {
c->data[0] = 2;
mg_http_reply(c, 200, "", "ok\n");
} else if (mg_match(hm->uri, mg_str("/api/kill"), NULL)) {
SCB->SHCSR &= ~SCB_SHCSR_USGFAULTENA_Msk;
__asm volatile("udf #0");
} else {
mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", hal_get_tick());
mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n",
hal_get_tick());
}
} else if (ev == MG_EV_CLOSE && c->data[0] == 1) {
MG_OTA_STATE_SET(MG_OTA_CONFIRMED);
NVIC_SystemReset();
} else if (ev == MG_EV_CLOSE && c->data[0] == 2) {
MG_OTA_STATE_SET(MG_OTA_CONFIRMED);
MG_OTA_ROLLBACK();
}
}
int main(void) {
hal_clock_init();
// Enable MemManage, BusFault and UsageFault so faults are precise and
// routed to their own handlers instead of escalating to HardFault
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk |
SCB_SHCSR_USGFAULTENA_Msk;
MG_OTA_BOOT_CHECK(); // Must be called after clock init
MG_HEALTH_INIT(); // Must be called after clock init
MG_HEALTH_INIT(); // Must be called after clock init
hal_uart_init(UART_DEBUG, UART_DEBUG_TX_PIN, UART_DEBUG_RX_PIN, 115200);
mg_log_set_fn(log_fn, UART_DEBUG);
@@ -132,17 +113,20 @@ int main(void) {
hal_gpio_output(LED3);
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
// Report the previous boot's crash backtrace, if any
if (mg_health_reason() == MG_HEALTH_RESET_FAULT) {
MG_INFO(("Previous boot faulted. Backtrace:"));
char buf[MG_HEALTH_BACKTRACE * 10 + 100];
mg_snprintf(buf, sizeof(buf), "%s",
"arm-none-eabi-addr2line -pfiaC -e firmware.elf");
for (int i = 0; i < MG_HEALTH_BACKTRACE; i++) {
if (mg_health_record.backtrace[i] == 0) break;
MG_INFO((" #%d 0x%08lx", i,
(unsigned long) mg_health_record.backtrace[i]));
mg_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " 0x%08lx",
mg_health_record.backtrace[i]);
}
// * (volatile uint32_t *) 0 = 123; // Deliberate fault: write to unmapped memory
// mg_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
MG_INFO(("Previous boot crashed! Analyse with: %s", buf));
}
// for (;;) (void) 0;
struct mg_mgr mgr;
mg_mgr_init(&mgr);
@@ -10,50 +10,10 @@
#define MG_ENABLE_CUSTOM_MILLIS 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_DRIVER_STM32H 1
#define MG_ENABLE_PACKED_FS 1
// Place Ethernet driver's buffers into the DMA-accessible RAM, see link.ld
#define MG_ETH_RAM __attribute__((section(".eth_ram")))
// #define MG_DRIVER_MDC_CR 4 // RMII MDC clock divider, from 0 to 5
// #define MG_TCPIP_PHY_ADDR 0 // PHY address
// For static IP configuration, define MG_TCPIP_{IP,MASK,GW}
// By default, those are set to zero, meaning that DHCP is used
//
// #define MG_TCPIP_IP MG_IPV4(192, 168, 0, 10) // IP
// #define MG_TCPIP_GW MG_IPV4(192, 168, 0, 1) // Gateway
// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) // Netmask
// OTA rollback timer via IWDG1. PR=7 → /512 on H723 (RM0468 §54.4.2).
// Fixed 10 s hang-detection window: RLR = 10 * 32000 / 512 = 625.
// RM0468 §54.4 sequence: 0xCCCC first (starts LSI), then 0x5555 to unlock,
// write PR+RLR, wait SR=0 (PVU|RVU), then 0xAAAA to reload the counter.
// mg_ota_poll() feeds the watchdog every 500ms while in MG_OTA_TESTING state.
#define MG_OTA_ROLLBACK_TIMER_START() \
do { \
IWDG1->KR = 0xCCCCU; /* start/LSI */ \
IWDG1->KR = 0x5555U; /* unlock */ \
IWDG1->PR = 7U; /* /512 */ \
IWDG1->RLR = 625U; /* 10 s */ \
while (IWDG1->SR & (IWDG_SR_PVU | IWDG_SR_RVU)) (void) 0; /* wait SR=0 */ \
IWDG1->KR = 0xAAAAU; /* reload */ \
} while (0)
#define MG_OTA_ROLLBACK_TIMER_FEED() (IWDG1->KR = 0xAAAAU)
// OTA state in RTC backup register 0 (survives all resets, clears on POR).
// Requires hal_backup_domain_init() (called from hal_clock_init) to have run.
#define MG_OTA_STATE_GET() (RTC->BKP0R)
#define MG_OTA_STATE_SET(v) (RTC->BKP0R = (uint32_t) (v))
// Health record lives in the .mg_health region, see link.ld
#define MG_HEALTH_RAM __attribute__((section(".mg_health")))
// mdash device token
#define MG_ENABLE_MDASH 1
#ifndef MG_MDASH_KEY
#define MG_MDASH_KEY "" // Set this
#endif
// Construct MAC address from the MCU unique ID
#define MGUID ((uint32_t *) UID_BASE)
#define MG_SET_MAC_ADDRESS(mac) \
@@ -65,3 +25,10 @@
mac[4] = MGUID[1] & 255; \
mac[5] = MGUID[2] & 255; \
} while (0)
// Crash report support. Health record lives in the .mg_health region, see link.ld
#define MG_HEALTH_RAM __attribute__((section(".mg_health")))
// mdash.net device management service support
#define MG_ENABLE_MDASH 1
#define MG_MDASH_KEY "u8eyWvBmkc6gw9991z1SQ8Lg" // Set this - mDash device token