Fixed a Partition boot issue due to XIP Cache
This commit is contained in:
1
projects/tzpuPico/.gdbinit.3333
vendored
1
projects/tzpuPico/.gdbinit.3333
vendored
@@ -1,4 +1,3 @@
|
||||
2
|
||||
|
||||
define xac
|
||||
dont-repeat
|
||||
|
||||
2
projects/tzpuPico/esp32/filepack_version.txt
vendored
2
projects/tzpuPico/esp32/filepack_version.txt
vendored
@@ -1 +1 @@
|
||||
2.0
|
||||
2.03
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
2
projects/tzpuPico/esp32/main/include/WiFi.h
vendored
2
projects/tzpuPico/esp32/main/include/WiFi.h
vendored
@@ -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];
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
2
projects/tzpuPico/esp32/version.txt
vendored
2
projects/tzpuPico/esp32/version.txt
vendored
@@ -1 +1 @@
|
||||
2.0
|
||||
2.03
|
||||
|
||||
28
projects/tzpuPico/esp32/webserver/index.htm
vendored
28
projects/tzpuPico/esp32/webserver/index.htm
vendored
@@ -187,22 +187,34 @@
|
||||
<h3 class="panel-title"><i class="fa fa-dashboard"></i> System Status</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-borderless table-sm" style="margin-bottom:0;">
|
||||
<table class="table table-borderless table-sm" style="margin-bottom:0; width:auto;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width:160px;">Firmware Version:</td><td><span style="color:#5bf;" id="sys-fwver">%SK_FWVERSION%</span></td>
|
||||
<td style="width:160px;">ESP32 Version:</td><td><span style="color:#5bf;" id="sys-espver">%SK_ESPVERSION%</span></td>
|
||||
<td style="width:140px; padding-right:4px;">Firmware Version:</td><td style="width:200px;"><span style="color:#5bf;">%SK_FWVERSION%</span></td>
|
||||
<td style="width:140px; padding-right:4px;">ESP32 Version:</td><td style="width:200px;"><span style="color:#5bf;">%SK_ESPVERSION%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Active Partition:</td><td><span style="color:#5bf;" id="sys-partition">%SK_ACTIVEPARTITION%</span></td>
|
||||
<td>Active Persona:</td><td><span style="color:#5bf;" id="sys-persona">%SK_PERSONA%</span></td>
|
||||
<td>Active Partition:</td><td><span style="color:#5bf;">%SK_ACTIVEPARTITION%</span></td>
|
||||
<td>Active Persona:</td><td><span style="color:#5bf;">%SK_PERSONA%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RP2350 Clock:</td><td><span style="color:#5bf;" id="sys-cpuclk">%SK_CPUCLOCK%</span></td>
|
||||
<td>PSRAM Clock:</td><td><span style="color:#5bf;" id="sys-psramclk">%SK_PSRAMCLOCK%</span></td>
|
||||
<td>RP2350 Clock:</td><td><span style="color:#5bf;">%SK_CPUCLOCK%</span></td>
|
||||
<td>ESP32 Clock:</td><td><span style="color:#5bf;">%SK_ESP32CLOCK%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SD Card:</td><td><span style="color:#5bf;" id="sys-sdcard">%SK_SDCARD%</span></td>
|
||||
<td>RP2350 Flash:</td><td><span style="color:#5bf;">%SK_RP2350FLASH%</span></td>
|
||||
<td>ESP32 Flash:</td><td><span style="color:#5bf;">%SK_ESP32FLASH%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RP2350 PSRAM:</td><td><span style="color:#5bf;">%SK_RP2350PSRAM%</span></td>
|
||||
<td>ESP32 PSRAM:</td><td><span style="color:#5bf;">%SK_ESP32PSRAM%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PSRAM Clock:</td><td><span style="color:#5bf;">%SK_PSRAMCLOCK%</span></td>
|
||||
<td>SD Card:</td><td><span style="color:#5bf;">%SK_SDCARD%</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FilePack:</td><td><span style="color:#5bf;">%SK_FILEPACK%</span></td>
|
||||
<td>Uptime:</td><td><span style="color:#5bf;" id="sys-uptime">%SK_UPTIME%</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.0
|
||||
2.03
|
||||
|
||||
@@ -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
|
||||
|
||||
2
projects/tzpuPico/src/include/FSPI.h
vendored
2
projects/tzpuPico/src/include/FSPI.h
vendored
@@ -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
|
||||
|
||||
2
projects/tzpuPico/src/include/flash_ram.h
vendored
2
projects/tzpuPico/src/include/flash_ram.h
vendored
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.0
|
||||
2.009
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/resets.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "hardware/xip_cache.h"
|
||||
#include <pico/printf.h>
|
||||
#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.
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.0
|
||||
2.004
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
2
projects/tzpuPico/version.txt
vendored
2
projects/tzpuPico/version.txt
vendored
@@ -1 +1 @@
|
||||
2.0
|
||||
2.011
|
||||
|
||||
Reference in New Issue
Block a user