fix(ota): 修复SPI OTA重传机制和跳转应用逻辑
- 主循环发送ACK时同步更新重发缓存,解决ISR先写WAIT后主循环发ACK不更新 缓存的问题,避免重发时返回过期WAIT导致ESP32永远接收WAIT而中止传输 - 在stay_in_ota状态结束跳转应用前增加CHECK/AVAL标志门控,防止在 OTA中途取消时verifyAppCrc的FLASH_EMPTY兜底逻辑误判通过,跳入半成品 固件导致GD32永久失联
This commit is contained in:
@@ -187,6 +187,18 @@ void SpiOta::sender(ota_link_tx_type_t type, u8 len, const u8 *data) {
|
||||
u16 built_len = 0U;
|
||||
if (buildFrame(rsp_type, data, len, frame_buf, &built_len)) {
|
||||
submitResponse(frame_buf, built_len);
|
||||
/* ★ 主循环发 ACK 时同步更新重发缓存(仅 ACK,不缓存 WAIT)。
|
||||
* 旧 bug:ISR 先写 WAIT 入缓存,主循环后续发 ACK 却不更新缓存,
|
||||
* 一旦该 ACK 帧因时序丢失,ESP32 重发触发 DUP-SEQ 时只能回放过期
|
||||
* WAIT → ESP32 永远只见 WAIT → stall 中止(特别在 8MHz 下必现)。
|
||||
* 现在重发会回放最终 ACK,实现“重发快且不漏”。 */
|
||||
if (type == OTA_LINK_TX_ACK && built_len > 0U && built_len <= sizeof(s_lastRespBuf)) {
|
||||
uint32_t primask = enterCritical();
|
||||
memcpy(s_lastRespBuf, frame_buf, built_len);
|
||||
s_lastRespLen = built_len;
|
||||
s_hasCachedResp = true;
|
||||
exitCritical(primask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-3
@@ -265,11 +265,28 @@ void BootloaderSystem::run() {
|
||||
was_active = true;
|
||||
idle_since = 0U;
|
||||
} else if (was_active) {
|
||||
/* 曾进入 OTA,现在回到 IDLE(CANCEL/超时/完成)→ 跳回 APP */
|
||||
/* 曾进入 OTA,现在回到 IDLE(CANCEL/超时/完成)→ 跳回 APP。
|
||||
*
|
||||
* ★ 必须与 OTA.cpp 超时路径一样用应用区标志门控:
|
||||
* eraseApplicationArea() 在 SIZE 阶段已把 CHECK/AVAL 置为
|
||||
* NOT_AVAL(0xFFFFFFFF),应用区处于“半擦/半写”状态;此时
|
||||
* verifyAppCrc() 的 FLASH_EMPTY 兜底(CRC 页已擦=0xFFFFFFFF
|
||||
* → 判“无 CRC 保护=有效”)会误判通过,跳入半成品固件:
|
||||
* 向量表已被前几包写入 → validateApplication 通过 → 直接
|
||||
* BX 到残缺代码 → HardFault → GD32 永久失联(SPI 全超时,
|
||||
* 日志特征:CANCEL 后 queryFeedback 全部 ESP_ERR_TIMEOUT)。
|
||||
* 只有标志仍为 AVAL(OTA 从未擦过应用区,旧固件完好)
|
||||
* 才允许跳回;中途中止则留在 BOOT 等重试/重启。 */
|
||||
flash_ptr = (volatile uint32_t *)n_APP_LATEST_CHECK_ADDR;
|
||||
const u32 ended_check = *flash_ptr;
|
||||
flash_ptr = (volatile uint32_t *)n_APP_LATEST_AVAL_ADDR;
|
||||
const u32 ended_aval = *flash_ptr;
|
||||
#if DEBUG_PRINT
|
||||
printf("[BOOT] stay_in_ota -> ota ended, jump app\r\n");
|
||||
printf("[BOOT] stay_in_ota -> ota ended, check=0x%08lX aval=0x%08lX\r\n",
|
||||
(unsigned long)ended_check, (unsigned long)ended_aval);
|
||||
#endif
|
||||
if (verifyAppCrc(APPLATEST_START_ADDR)) {
|
||||
if (ended_check == OTA_AVAL && ended_aval == OTA_AVAL &&
|
||||
verifyAppCrc(APPLATEST_START_ADDR)) {
|
||||
ota.jumpToApplication();
|
||||
}
|
||||
/* jumpToApplication 失败(CRC/向量不合法)则留在 BOOT */
|
||||
|
||||
@@ -16,7 +16,7 @@ typedef uint32_t u32;
|
||||
#define BOOT_FW_VERSION_MAJOR 1U
|
||||
#define BOOT_FW_VERSION_MINOR 1U
|
||||
#define BOOT_FW_VERSION_PATCH 0U
|
||||
#define BOOT_FW_VERSION_BUILD 1U
|
||||
#define BOOT_FW_VERSION_BUILD 3U /* v1.1.0.3: stay_in_ota 跳回 APP 前加 CHECK/AVAL 标志门控,修复中断 OTA 后 verifyAppCrc FLASH_EMPTY 误判跳入半成品固件导致 GD32 永久失联 */
|
||||
|
||||
/**
|
||||
* Flash 布局说明(GD32E508VE,512KB)
|
||||
|
||||
Reference in New Issue
Block a user