diff --git a/tutorials/stm32/nucleo-h723zg/cubemx/mongoose/mongoose_config.h b/tutorials/stm32/nucleo-h723zg/cubemx/mongoose/mongoose_config.h index 2e577dfa..6fe59481 100644 --- a/tutorials/stm32/nucleo-h723zg/cubemx/mongoose/mongoose_config.h +++ b/tutorials/stm32/nucleo-h723zg/cubemx/mongoose/mongoose_config.h @@ -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 diff --git a/tutorials/stm32/nucleo-h723zg/minimal/main.c b/tutorials/stm32/nucleo-h723zg/minimal/main.c index 118ab0eb..a08edaf9 100644 --- a/tutorials/stm32/nucleo-h723zg/minimal/main.c +++ b/tutorials/stm32/nucleo-h723zg/minimal/main.c @@ -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); diff --git a/tutorials/stm32/nucleo-h723zg/minimal/mongoose_config.h b/tutorials/stm32/nucleo-h723zg/minimal/mongoose_config.h index cdfe6378..097774f1 100644 --- a/tutorials/stm32/nucleo-h723zg/minimal/mongoose_config.h +++ b/tutorials/stm32/nucleo-h723zg/minimal/mongoose_config.h @@ -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