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
-
+
- | 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% |
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