From 881364b9feb42dc6c81ffe4b7261a074d28fe4f5 Mon Sep 17 00:00:00 2001 From: Philip Smart Date: Sat, 28 Mar 2026 18:53:44 +0000 Subject: [PATCH] Fixed a Partition boot issue due to XIP Cache --- projects/tzpuPico/.gdbinit.3333 | 1 - projects/tzpuPico/esp32/filepack_version.txt | 2 +- projects/tzpuPico/esp32/main/SDCard.cpp | 10 +++- projects/tzpuPico/esp32/main/WiFi.cpp | 49 ++++++++++++++++- projects/tzpuPico/esp32/main/include/WiFi.h | 2 + .../tzpuPico/esp32/main/include/flash_ram.h | 2 + projects/tzpuPico/esp32/main/tzpuPico.cpp | 17 ++++++ projects/tzpuPico/esp32/version.txt | 2 +- projects/tzpuPico/esp32/webserver/index.htm | 28 +++++++--- .../esp32/webserver/webfs_version.txt | 2 +- projects/tzpuPico/src/ESP.c | 7 +++ projects/tzpuPico/src/include/FSPI.h | 2 +- projects/tzpuPico/src/include/flash_ram.h | 2 + projects/tzpuPico/src/model/BaseZ80/main.c | 26 ++++++++- .../model/BaseZ80/main_memmap_partition_2.ld | 2 +- .../tzpuPico/src/model/BaseZ80/version.txt | 2 +- .../src/model/Bootloader/Bootloader.c | 28 ++++++++++ .../tzpuPico/src/model/Bootloader/version.txt | 2 +- projects/tzpuPico/src/usb_bridge.c | 55 ++++++++++++------- projects/tzpuPico/version.txt | 2 +- 20 files changed, 200 insertions(+), 43 deletions(-) diff --git a/projects/tzpuPico/.gdbinit.3333 b/projects/tzpuPico/.gdbinit.3333 index b3250ca..ab5a975 100644 --- a/projects/tzpuPico/.gdbinit.3333 +++ b/projects/tzpuPico/.gdbinit.3333 @@ -1,4 +1,3 @@ -2 define xac dont-repeat diff --git a/projects/tzpuPico/esp32/filepack_version.txt b/projects/tzpuPico/esp32/filepack_version.txt index cd5ac03..42ea6ce 100644 --- a/projects/tzpuPico/esp32/filepack_version.txt +++ b/projects/tzpuPico/esp32/filepack_version.txt @@ -1 +1 @@ -2.0 +2.03 diff --git a/projects/tzpuPico/esp32/main/SDCard.cpp b/projects/tzpuPico/esp32/main/SDCard.cpp index 83d67de..7b4a778 100644 --- a/projects/tzpuPico/esp32/main/SDCard.cpp +++ b/projects/tzpuPico/esp32/main/SDCard.cpp @@ -814,15 +814,19 @@ bool SDCard::storeRP2350Info(const t_IpcFrameHdr &frame, FSPI &fspi) { memcpy(rp2350Header, infoBuf, sizeof(t_FlashPartitionHeader)); - // Extended payload includes cpufreq/psramfreq/voltage after the header. + // Extended payload includes cpufreq/psramfreq/voltage/flashSize/psramSize after the header. if (payloadSize >= sizeof(t_FlashInfoPayload)) { t_FlashInfoPayload *info = (t_FlashInfoPayload *) infoBuf; - // Store in the 3 int32_t fields immediately after rp2350FlashHeader in wifiCtrl.run - int32_t *extra = (int32_t *) (rp2350Header + 1); // pointer arithmetic: past the header + // Store in the fields immediately after rp2350FlashHeader in wifiCtrl.run. + // Layout must match: int32_t cpufreq, psramfreq, voltage; uint32_t flashSize, psramSize; + int32_t *extra = (int32_t *) (rp2350Header + 1); extra[0] = info->cpufreq; extra[1] = info->psramfreq; extra[2] = info->voltage; + uint32_t *extra32 = (uint32_t *) &extra[3]; + extra32[0] = info->flashSize; + extra32[1] = info->psramSize; } } free(infoBuf); diff --git a/projects/tzpuPico/esp32/main/WiFi.cpp b/projects/tzpuPico/esp32/main/WiFi.cpp index a002df1..de3304c 100644 --- a/projects/tzpuPico/esp32/main/WiFi.cpp +++ b/projects/tzpuPico/esp32/main/WiFi.cpp @@ -64,6 +64,8 @@ #include "esp_event.h" #include "esp_ota_ops.h" #include "esp_timer.h" +#include "esp_flash.h" +#include "esp_psram.h" #include "lwip/err.h" #include "lwip/sys.h" #include "driver/uart.h" @@ -872,6 +874,36 @@ esp_err_t WiFi::expandVarsAndSend(httpd_req_t *req, std::string str) std::to_string(wifiCtrl.run.rp2350PsramFreq / 1000000) + " MHz" : "N/A"; pairs.push_back(keyValue); + // RP2350 Flash and PSRAM sizes — dynamic from INF payload. + keyValue.name = "%SK_RP2350FLASH%"; + keyValue.value = (wifiCtrl.run.rp2350FlashSize > 0) ? + std::to_string(wifiCtrl.run.rp2350FlashSize / (1024 * 1024)) + " MB" : "N/A"; + pairs.push_back(keyValue); + + keyValue.name = "%SK_RP2350PSRAM%"; + keyValue.value = (wifiCtrl.run.rp2350PsramSize > 0) ? + std::to_string(wifiCtrl.run.rp2350PsramSize / (1024 * 1024)) + " MB" : "N/A"; + pairs.push_back(keyValue); + + // ESP32 info — available directly from ESP-IDF APIs. + keyValue.name = "%SK_ESP32CLOCK%"; + keyValue.value = std::to_string(CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) + " MHz"; + pairs.push_back(keyValue); + + keyValue.name = "%SK_ESP32FLASH%"; + { + // Use physical size (actual chip) not image header size (may be smaller). + uint32_t flashSize = 0; + if (esp_flash_get_physical_size(NULL, &flashSize) != ESP_OK) + esp_flash_get_size(NULL, &flashSize); // Fallback to image header size + keyValue.value = (flashSize > 0) ? std::to_string(flashSize / (1024 * 1024)) + " MB" : "N/A"; + } + pairs.push_back(keyValue); + + keyValue.name = "%SK_ESP32PSRAM%"; + keyValue.value = std::to_string(esp_psram_get_size() / (1024 * 1024)) + " MB"; + pairs.push_back(keyValue); + keyValue.name = "%SK_SDCARD%"; keyValue.value = (sdcard != NULL) ? "Mounted" : "Not available"; pairs.push_back(keyValue); @@ -1914,20 +1946,24 @@ esp_err_t WiFi::otaFetchFile(httpd_req_t *req, const std::string &createFileName // Build the FQFN of the file to create. std::string fqfn = pThis->wifiCtrl.run.fsPath + fileDir + '/' + createFileName; - ESP_LOGI(WIFITAG, "File to create => %s", fqfn.c_str()); + ESP_LOGI(WIFITAG, "FW_FETCH: file=%s content_len=%d heap=%lu", fqfn.c_str(), req->content_len, (unsigned long) esp_get_free_heap_size()); // Open a stream on the SD card temp directory in which to place the received data. outFile.open(fqfn.c_str()); if (outFile.is_open()) { + ESP_LOGI(WIFITAG, "FW_FETCH: file opened OK"); chunk.reset(new char[MAX_CHUNK_SIZE]); if (chunk == nullptr) { result = ESP_FAIL; + ESP_LOGE(WIFITAG, "FW_FETCH: chunk alloc failed"); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory exhausted in otaFetchFile"); } remaining = req->content_len; + ESP_LOGI(WIFITAG, "FW_FETCH: starting recv loop, remaining=%d", remaining); + int chunkCount = 0; while (remaining > 0 && result == ESP_OK) { chunkSize = httpd_req_recv(req, chunk.get(), MIN(remaining, MAX_CHUNK_SIZE)); @@ -1937,6 +1973,7 @@ esp_err_t WiFi::otaFetchFile(httpd_req_t *req, const std::string &createFileName { continue; } + ESP_LOGE(WIFITAG, "FW_FETCH: recv error chunkSize=%d remaining=%d", (int) chunkSize, remaining); result = ESP_FAIL; int sockFd = httpd_req_to_sockfd(req); if (sockFd != -1) @@ -1946,14 +1983,18 @@ esp_err_t WiFi::otaFetchFile(httpd_req_t *req, const std::string &createFileName { outFile.write(chunk.get(), chunkSize); remaining -= chunkSize; + chunkCount++; + if ((chunkCount % 10) == 0) + ESP_LOGI(WIFITAG, "FW_FETCH: chunk %d, remaining=%d", chunkCount, remaining); } } outFile.close(); + ESP_LOGI(WIFITAG, "FW_FETCH: done, chunks=%d result=%d", chunkCount, result); } else { result = ESP_FAIL; - ESP_LOGI(WIFITAG, "Failed to create file:%s", fqfn.c_str()); + ESP_LOGE(WIFITAG, "FW_FETCH: failed to create file:%s", fqfn.c_str()); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to create local temporary file"); } @@ -2063,6 +2104,8 @@ esp_err_t WiFi::reqRP2350FWUpdate(char *errMsg, pageBuffer[bufIdx++] = (uint8_t) (0); pageBuffer[bufIdx++] = (uint8_t) (0); pageBuffer[bufIdx++] = (uint8_t) (instance); + ESP_LOGI(WIFITAG, "FW_AUTH: instance=%d addr=%08lx size=%08lx chksum=%08lx", + instance, rp2350Addr, fileSize, fwChkSum); pageBuffer[bufIdx++] = (uint8_t) (fwChkSum >> 24); pageBuffer[bufIdx++] = (uint8_t) (fwChkSum >> 16); pageBuffer[bufIdx++] = (uint8_t) (fwChkSum >> 8); @@ -2337,12 +2380,14 @@ esp_err_t WiFi::otaRP2350FirmwareUpdatePOSTHandler(httpd_req_t *req) { *(errMsg) = 0x00; + ESP_LOGI(WIFITAG, "FW_UPD: fetching file from browser..."); if (pThis->otaFetchFile(req, WIFI_RP2350_FW_FILENAME) != ESP_OK) { sprintf((errMsg + strlen(errMsg)), "Failed to fetch firmware file => %s\n", fqfnBIN.c_str()); } else { + ESP_LOGI(WIFITAG, "FW_UPD: file saved, opening binary..."); inFile.open(fqfnBIN.c_str(), std::ios::binary); inFile.seekg(0, inFile.end); fileSize = inFile.tellg(); diff --git a/projects/tzpuPico/esp32/main/include/WiFi.h b/projects/tzpuPico/esp32/main/include/WiFi.h index af9daab..f2a8599 100644 --- a/projects/tzpuPico/esp32/main/include/WiFi.h +++ b/projects/tzpuPico/esp32/main/include/WiFi.h @@ -317,6 +317,8 @@ class WiFi int32_t rp2350CpuFreq; // RP2350 CPU freq in Hz (from INF) int32_t rp2350PsramFreq; // PSRAM freq in Hz (from INF) int32_t rp2350Voltage; // Core voltage (from INF) + uint32_t rp2350FlashSize; // RP2350 Flash size in bytes (from INF) + uint32_t rp2350PsramSize; // RP2350 PSRAM size in bytes (from INF) // Active Floppy Disk images. std::string floppyDiskImage[WIFI_MAX_FLOPPY_DISK_IMAGES]; diff --git a/projects/tzpuPico/esp32/main/include/flash_ram.h b/projects/tzpuPico/esp32/main/include/flash_ram.h index 7787233..3015cef 100644 --- a/projects/tzpuPico/esp32/main/include/flash_ram.h +++ b/projects/tzpuPico/esp32/main/include/flash_ram.h @@ -159,6 +159,8 @@ typedef struct int32_t cpufreq; // RP2350 CPU frequency in Hz (0 = default) int32_t psramfreq; // PSRAM SPI frequency in Hz (0 = default) int32_t voltage; // Core voltage setting (VREG enum) + uint32_t flashSize; // RP2350 Flash size in bytes + uint32_t psramSize; // RP2350 PSRAM size in bytes } t_FlashInfoPayload; // Structure to describe a single file stored in ROM. Indexed by its filename (matching a filename appearing in JSON including path) diff --git a/projects/tzpuPico/esp32/main/tzpuPico.cpp b/projects/tzpuPico/esp32/main/tzpuPico.cpp index e8a7b90..e243807 100644 --- a/projects/tzpuPico/esp32/main/tzpuPico.cpp +++ b/projects/tzpuPico/esp32/main/tzpuPico.cpp @@ -611,6 +611,23 @@ extern "C" // void app_main() { + // Log the reset reason FIRST — critical for diagnosing unexpected reboots. + esp_reset_reason_t rstReason = esp_reset_reason(); + const char *rstName; + switch (rstReason) + { + case ESP_RST_POWERON: rstName = "POWERON"; break; + case ESP_RST_EXT: rstName = "EXT_PIN"; break; + case ESP_RST_SW: rstName = "SW_RESET"; break; + case ESP_RST_PANIC: rstName = "PANIC"; break; + case ESP_RST_INT_WDT: rstName = "INT_WDT"; break; + case ESP_RST_TASK_WDT: rstName = "TASK_WDT"; break; + case ESP_RST_WDT: rstName = "OTHER_WDT"; break; + case ESP_RST_BROWNOUT: rstName = "BROWNOUT"; break; + default: rstName = "UNKNOWN"; break; + } + ESP_LOGW(MAINTAG, "=== ESP32 BOOT === reset reason: %d (%s)", (int) rstReason, rstName); + // Locals. static NVS nvs; static SDCard sdcard; diff --git a/projects/tzpuPico/esp32/version.txt b/projects/tzpuPico/esp32/version.txt index cd5ac03..42ea6ce 100644 --- a/projects/tzpuPico/esp32/version.txt +++ b/projects/tzpuPico/esp32/version.txt @@ -1 +1 @@ -2.0 +2.03 diff --git a/projects/tzpuPico/esp32/webserver/index.htm b/projects/tzpuPico/esp32/webserver/index.htm index c15fac4..2e1ce76 100644 --- a/projects/tzpuPico/esp32/webserver/index.htm +++ b/projects/tzpuPico/esp32/webserver/index.htm @@ -187,22 +187,34 @@

System Status

- +
- - + + - - + + - - + + - + + + + + + + + + + + + + diff --git a/projects/tzpuPico/esp32/webserver/webfs_version.txt b/projects/tzpuPico/esp32/webserver/webfs_version.txt index cd5ac03..42ea6ce 100644 --- a/projects/tzpuPico/esp32/webserver/webfs_version.txt +++ b/projects/tzpuPico/esp32/webserver/webfs_version.txt @@ -1 +1 @@ -2.0 +2.03 diff --git a/projects/tzpuPico/src/ESP.c b/projects/tzpuPico/src/ESP.c index 4246edc..55e961c 100644 --- a/projects/tzpuPico/src/ESP.c +++ b/projects/tzpuPico/src/ESP.c @@ -54,6 +54,9 @@ static t_ESP *esp; // Sequence counter for binary IPC frames — incremented per command for retry detection. static uint8_t gIpcSeq = 0; +// PSRAM size from main.c — populated by psram_init() at boot. +extern size_t psramSize; + // Source was originally C++, so this is the destructor. void ESP_deinit(void) { @@ -134,6 +137,10 @@ bool ESP_sendVersionInfo(void) infPayload.voltage = 0; } + // Hardware sizes — always available regardless of config. + infPayload.flashSize = PICO_FLASH_SIZE_BYTES; + infPayload.psramSize = psramSize; // Set during psram_init() at boot + // Send INF command — payload is the extended flash info. // Only attempt if ESP32 HS is already HIGH (CommandProcessor ready). // INF is non-critical (web interface version display only); the Z80 diff --git a/projects/tzpuPico/src/include/FSPI.h b/projects/tzpuPico/src/include/FSPI.h index 6469c63..4782dbd 100644 --- a/projects/tzpuPico/src/include/FSPI.h +++ b/projects/tzpuPico/src/include/FSPI.h @@ -72,7 +72,7 @@ // At 50MHz the SPI RX FIFO (4 bytes deep) can overflow when core-1 Z80/PSRAM // accesses stall the AHB crossbar, causing dropped bytes mid-transfer and CRC mismatches. // If too many CRC errors are seen in the log, reduce the frequency. -#define FSPI_CLK_FREQ 50 * 1000 * 1000 +#define FSPI_CLK_FREQ 25 * 1000 * 1000 #define FSPI_DATABITS_PER_XFER 8 #define FSPI_DATA_POLARITY SPI_CPOL_1 #define FSPI_DATA_PHASE SPI_CPHA_1 diff --git a/projects/tzpuPico/src/include/flash_ram.h b/projects/tzpuPico/src/include/flash_ram.h index 1d49ff5..2a80e9d 100644 --- a/projects/tzpuPico/src/include/flash_ram.h +++ b/projects/tzpuPico/src/include/flash_ram.h @@ -161,6 +161,8 @@ typedef struct int32_t cpufreq; // RP2350 CPU frequency in Hz (0 = default) int32_t psramfreq; // PSRAM SPI frequency in Hz (0 = default) int32_t voltage; // Core voltage setting (VREG enum) + uint32_t flashSize; // RP2350 Flash size in bytes (from PICO_FLASH_SIZE_BYTES) + uint32_t psramSize; // RP2350 PSRAM size in bytes (from psram_init) } t_FlashInfoPayload; // Structure to describe a single file stored in ROM. Indexed by its filename (matching a filename appearing in JSON including path) diff --git a/projects/tzpuPico/src/model/BaseZ80/main.c b/projects/tzpuPico/src/model/BaseZ80/main.c index e3aac60..f06086a 100644 --- a/projects/tzpuPico/src/model/BaseZ80/main.c +++ b/projects/tzpuPico/src/model/BaseZ80/main.c @@ -186,7 +186,7 @@ static t_FlashAppConfigHeader *flashAppConfigHeader; //struct semaphore core1StartSem; static t_Z80CPU *z80CPU = NULL; -static size_t psramSize; +size_t psramSize; // Global — used by ESP.c for INF payload // Queue definitions (global, shared by ALL devices — referenced via z80CPU->requestQueue/responseQueue) static queue_t requestQueue __attribute__((unused)); @@ -1270,6 +1270,11 @@ void processInterCoreCommands(void) // Main entry point int main(void) { + // ABSOLUTE FIRST: Enable watchdog for recovery if partition 2 hangs. + // Do NOT write scratch registers here — they hold the previous boot's + // diagnostic data which we need to read below. + watchdog_enable(30000, true); + // Locals. uint32_t taskCount = 100; bool clkInit = false; @@ -1491,6 +1496,13 @@ int main(void) } bootStage(BOOTP_CORE1_LAUNCH); + // Ensure Core 1 is in a clean state before launch. After an AIRCR system + // reset (used by partition switch and firmware update), Core 1 may not have + // finished its bootrom parking sequence by the time Core 0 reaches here. + // multicore_reset_core1 forces Core 1 back to the bootrom wait loop. + multicore_reset_core1(); + sleep_ms(10); + // Setup core 1 to run the Z80 CPU. multicore_launch_core1(core1Main); @@ -1667,6 +1679,18 @@ int main(void) debugf("*** WATCHDOG RESET — no valid previous stage (magic=0x%08lX) ***\r\n", prevMagic); } + // Show bootloader's boot decision from scratch[4] (set by bootloader before branchToApp). + // scratch[4] is SPIDIAG — overwritten later at line ~1347, so read it NOW. + { + uint32_t blDecision = watchdog_hw->scratch[BOOTP_SCR_SPIDIAG]; + if ((blDecision & 0xFFFF0000) == 0xB0070000) + debugf(" Bootloader: BRANCH to app %d\r\n", blDecision & 0xFF); + else if ((blDecision & 0xFFFF0000) == 0xFA110000) + debugf(" Bootloader: VALIDATION FAILED for app %d\r\n", blDecision & 0xFF); + else if ((blDecision & 0xFFFF0000) == 0xBAD00000) + debugf(" Bootloader: PRE-CHECK FAILED for app %d\r\n", blDecision & 0xFF); + } + // Check PSRAM for fault diagnostic data from a previous boot's crash. // The fault handler writes to PSRAM_DIAG_ADDR (0x117FFF00) which survives // watchdog resets. This captures faults that occur before USB is ready. diff --git a/projects/tzpuPico/src/model/BaseZ80/main_memmap_partition_2.ld b/projects/tzpuPico/src/model/BaseZ80/main_memmap_partition_2.ld index 8469201..9db1baa 100644 --- a/projects/tzpuPico/src/model/BaseZ80/main_memmap_partition_2.ld +++ b/projects/tzpuPico/src/model/BaseZ80/main_memmap_partition_2.ld @@ -23,7 +23,7 @@ MEMORY { - /* 128K offset as the bootloader occupies the first block. */ + /* Partition 2: starts after bootloader (128K) + App1 (5MB) = offset 0x520000. */ FLASH(rx) : ORIGIN = 0x10520000, LENGTH = (16 * 1024 * 1024) - 0x520000 /* FLASH(rx) : ORIGIN = 0x10000000, LENGTH = (16 * 1024 * 1024) */ PSRAM(rwx) : ORIGIN = 0x11000000, LENGTH = (8 * 1024 * 1024) diff --git a/projects/tzpuPico/src/model/BaseZ80/version.txt b/projects/tzpuPico/src/model/BaseZ80/version.txt index cd5ac03..acb8ce8 100644 --- a/projects/tzpuPico/src/model/BaseZ80/version.txt +++ b/projects/tzpuPico/src/model/BaseZ80/version.txt @@ -1 +1 @@ -2.0 +2.009 diff --git a/projects/tzpuPico/src/model/Bootloader/Bootloader.c b/projects/tzpuPico/src/model/Bootloader/Bootloader.c index 0d9bda5..9fa0bfe 100644 --- a/projects/tzpuPico/src/model/Bootloader/Bootloader.c +++ b/projects/tzpuPico/src/model/Bootloader/Bootloader.c @@ -38,6 +38,7 @@ #include "hardware/clocks.h" #include "hardware/resets.h" #include "hardware/watchdog.h" +#include "hardware/xip_cache.h" #include #include "rp2350.h" #include "flash_ram.h" @@ -289,8 +290,35 @@ int main() (APP_FLASH_CONTENTS[header->config[header->activeApp].addr - HW_FLASHADDR_START + FLASH_APP_SIG_POS + 2] == FLASH_APP_SIG_BYTE_3) && (APP_FLASH_CONTENTS[header->config[header->activeApp].addr - HW_FLASHADDR_START + FLASH_APP_SIG_POS + 3] == FLASH_APP_SIG_BYTE_4))) { + // Record boot decision in scratch[4] — survives watchdog resets. + watchdog_hw->scratch[4] = 0xB0070000 | header->activeApp; + + // Enable watchdog BEFORE branchToApp — if the app crashes during + // CRT startup (before its own watchdog_enable in main()), this ensures + // automatic recovery instead of a permanent hang. + watchdog_enable(30000, true); + + // Invalidate XIP cache before branching — the bootloader ran from + // 0x10000000 and the cache holds entries from that range. Without + // invalidation, cache aliasing or stale prefetch state can cause + // the app at a different flash address (e.g. 0x10520000) to hang + // during CRT startup. This was the root cause of partition 2 boot + // failures — GDB's reset cleared the cache, which is why loading + // via GDB "fixed" it. + xip_cache_invalidate_all(); + branchToApp(header->activeApp); } + else + { + // Validation failed. + watchdog_hw->scratch[4] = 0xFA110000 | header->activeApp; + } + } + else + { + // Pre-validation check failed. + watchdog_hw->scratch[4] = 0xBAD00000 | header->activeApp; } // Initialise debug output buffers. diff --git a/projects/tzpuPico/src/model/Bootloader/version.txt b/projects/tzpuPico/src/model/Bootloader/version.txt index cd5ac03..51c8bae 100644 --- a/projects/tzpuPico/src/model/Bootloader/version.txt +++ b/projects/tzpuPico/src/model/Bootloader/version.txt @@ -1 +1 @@ -2.0 +2.004 diff --git a/projects/tzpuPico/src/usb_bridge.c b/projects/tzpuPico/src/usb_bridge.c index f567ca9..be295a8 100644 --- a/projects/tzpuPico/src/usb_bridge.c +++ b/projects/tzpuPico/src/usb_bridge.c @@ -1146,8 +1146,9 @@ void updateFlashSectors(uint32_t flashAddr, uint8_t *src, uint32_t sectors) // void updateFlashPartitionHeader(t_FlashPartitionHeader *header) { - // Locals. - uint8_t flashbuf[FW_SECTOR_SIZE]; + // Static buffer — 4KB on the stack is dangerous in the bootloader context + // and can overflow into adjacent stack frames, corrupting data silently. + static uint8_t flashbuf[FW_SECTOR_SIZE]; // Clear the flash header. Erase is 1 Sector, ie. 4096 bytes. flash_range_erase(FLASH_HEADER_OFFSET, FW_SECTOR_SIZE); @@ -1347,18 +1348,13 @@ void pollUSBtoUART(void) (flashPartitionInstance.addr % FW_PAGE_SIZE == 0) && (flashPartitionInstance.size < HW_FLASHADDR_SIZE) && (flashPartitionInstance.addr + flashPartitionInstance.size < HW_FLASHADDR_END)) { -#if defined(BOOTLOADER_DEBUG) - debugf("First frame ok: addr=%0lx, size=%0lx, flashAddr=%0lx -> %s,%s,%s,%s,%s,%s\r\n", + // Always log first frame details — critical for diagnosing partition issues. + debugf("AUTH OK: inst=%d addr=%0lx size=%0lx flashOfs=%0lx chksum=%0lx\r\n", + updInstance, flashPartitionInstance.addr, flashPartitionInstance.size, flashAddr, - flashPartitionInstance.license, - flashPartitionInstance.author, - flashPartitionInstance.description, - flashPartitionInstance.version, - flashPartitionInstance.versionDate, - flashPartitionInstance.copyright); -#endif + flashPartitionInstance.chksum); // Ok to send response now, data confirmed. ud->fwFirstFrame = false; @@ -1522,26 +1518,37 @@ void pollUSBtoUART(void) flashPartitionInstance.cfgSize = FLASH_APP_CONFIG_SIZE; memcpy(&flashPartitionHeader.config[updInstance], &flashPartitionInstance, sizeof(t_FlashPartitionInstance)); + // Diagnostic — always print the partition update details. + debugf("FW_UPD: inst=%d addr=%0lx size=%0lx chksum=%0lx activeApp=%d\r\n", + updInstance, + flashPartitionHeader.config[updInstance].addr, + flashPartitionHeader.config[updInstance].size, + flashPartitionHeader.config[updInstance].chksum, + flashPartitionHeader.activeApp); + // Update the flash header with latest config changes. - updateFlashPartitionHeader(&flashPartitionHeader); + // Interrupts MUST be disabled during flash erase/program — the UART ISR + // runs from flash and would hard-fault if it fires during the operation. + { + uint32_t ints = save_and_disable_interrupts(); + updateFlashPartitionHeader(&flashPartitionHeader); + restore_interrupts(ints); + } // Clear configuration flash RAM for this instance? if (ud->fwCfgClearMode) { debugf("Clearing config, partition:%d\r\n", updInstance); + uint32_t ints = save_and_disable_interrupts(); clearFlashConfig(updInstance); + restore_interrupts(ints); } // Send success. putUART(ui->inst, FW_RESP_FW_OK); -#if defined(BOOTLOADER_DEBUG) - // End of line, we are to reboot so make debug tidy. - debugf("\r\nFirmware OK (%0lx, %0lx, %0lx)\r\n", - flashPartitionHeader.config[updInstance].addr, - flashPartitionHeader.config[updInstance].size, - flashPartitionHeader.config[updInstance].chksum); -#endif + // Diagnostic — confirm completion. + debugf("FW_UPD: FW_OK sent, rebooting...\r\n"); // Need to flush out serial debug data if present, so enter loop to service the USB and UART buffers. for (int idx = 0; idx < 250; idx++) @@ -1551,8 +1558,13 @@ void pollUSBtoUART(void) sleep_ms(10); } - // Finally, reboot using the watchdog. + // Reboot: try both methods to ensure the reset fires. + // The flush loop above keeps Core 0 busy in pollUSBtoUART too (both + // cores call bridgeUSBtoUART). After the loop, trigger reset. watchdog_reboot(0, 0, 0); + busy_wait_ms(10); + *((volatile uint32_t *)(PPB_BASE + 0x0ED0C)) = 0x05FA0004; + while (1) { tight_loop_contents(); } } } else @@ -1574,6 +1586,9 @@ void pollUSBtoUART(void) if (++ud->fwTimeoutCnt > FW_MAX_TIMEOUT_CNT) { watchdog_reboot(0, 0, 0); + busy_wait_ms(10); + *((volatile uint32_t *)(PPB_BASE + 0x0ED0C)) = 0x05FA0004; + while (1) { tight_loop_contents(); } } else { diff --git a/projects/tzpuPico/version.txt b/projects/tzpuPico/version.txt index cd5ac03..da5a635 100644 --- a/projects/tzpuPico/version.txt +++ b/projects/tzpuPico/version.txt @@ -1 +1 @@ -2.0 +2.011
Firmware Version:%SK_FWVERSION%ESP32 Version:%SK_ESPVERSION%Firmware Version:%SK_FWVERSION%ESP32 Version:%SK_ESPVERSION%
Active Partition:%SK_ACTIVEPARTITION%Active Persona:%SK_PERSONA%Active Partition:%SK_ACTIVEPARTITION%Active Persona:%SK_PERSONA%
RP2350 Clock:%SK_CPUCLOCK%PSRAM Clock:%SK_PSRAMCLOCK%RP2350 Clock:%SK_CPUCLOCK%ESP32 Clock:%SK_ESP32CLOCK%
SD Card:%SK_SDCARD%RP2350 Flash:%SK_RP2350FLASH%ESP32 Flash:%SK_ESP32FLASH%
RP2350 PSRAM:%SK_RP2350PSRAM%ESP32 PSRAM:%SK_ESP32PSRAM%
PSRAM Clock:%SK_PSRAMCLOCK%SD Card:%SK_SDCARD%
FilePack:%SK_FILEPACK% Uptime:%SK_UPTIME%