修复IWDG超时未配置与dhara resume回滚:看门狗误复位与复位后写入全部丢失,台架全量自检PASS

This commit is contained in:
2026-10-02 20:48:30 +08:00
parent d1a2eaab07
commit 930215f81a
33 changed files with 1875 additions and 94 deletions
+20
View File
@@ -144,11 +144,26 @@ static int gd5f_dma_buf_ok(const void *p_buf, size_t size) {
* 限定条件:SPI 已初始化
* 函数说明:循环读取状态寄存器直到 OIP 位清零或超时
*/
/* 看门狗心跳弱钩子:默认空实现(无看门狗/模拟器构建);强符号由
* App/util/task_watchdog.c 提供,路由到调用者任务的心跳位 */
__weak void nand_ftl_wd_beat(void) {
}
/* 看门狗直接喂狗弱钩子:默认空实现;强符号由 App/util/task_watchdog.c
* 提供(IWDG 已启动时写 KR)——覆盖 defaultTask(喂狗点)自身陷于长 FTL
* 操作、主循环喂狗停摆的形态(2026-10-02 台架实证) */
__weak void nand_ftl_wd_feed(void) {
}
int gd5f_wait_busy(uint32_t timeout_ms) {
uint8_t cmd = GD5F_CMD_GET_FEATURE;
uint8_t addr = GD5F_REG_STATUS;
uint8_t status = 0;
uint32_t tick_start = HAL_GetTick();
uint32_t last_beat = tick_start;
nand_ftl_wd_beat(); /* 看门狗:入口心跳(长操作在调用者任务上下文;内核前调用为空操作) */
nand_ftl_wd_feed(); /* 看门狗:入口直接喂狗(覆盖 defaultTask 长 I/O 阻塞主循环喂狗点的形态) */
while (1) {
GD5F_CS_LOW();
@@ -163,6 +178,11 @@ int gd5f_wait_busy(uint32_t timeout_ms) {
if ((HAL_GetTick() - tick_start) >= timeout_ms) {
return GD5F_BUSY_TIMEOUT;
}
if ((uint32_t)(HAL_GetTick() - last_beat) >= 100u) {
last_beat = HAL_GetTick();
nand_ftl_wd_beat(); /* 看门狗:循环内每 100 ms 心跳(擦除等待最长 5 s) */
nand_ftl_wd_feed(); /* 看门狗:同步直接喂狗(同节奏) */
}
}
}
+30
View File
@@ -247,6 +247,36 @@ int32_t gd5f_program_exec(uint32_t page_addr);
int32_t gd5f_block_erase(uint32_t block_addr);
int32_t gd5f_check_ecc(void);
/*
* 函数功能:NAND 长耗时操作看门狗心跳弱钩子
* 入口参数:无
* 返回值:无
* 限定条件:任意上下文可调(内核启动前调用为空操作)
* 函数说明:gd5f_wait_busy 的长轮询(块擦除等待最长 5 s、GC 页拷贝、
* 日志写)都运行在调用者任务上下文(default/ftp/ui/timesync 等);
* 本钩子默认空实现,App/util/task_watchdog.c 提供强符号,按调用者
* 任务句柄路由到该任务的心跳位,防止长耗时窗口心跳缺席导致 IWDG
* 误复位(2026-10-02 台架:0 字节 STOR 截断 → dhara GC > 800 ms
* 无心跳 → 停喂 → IWDG 误复位)。
*/
void nand_ftl_wd_beat(void);
/*
* 函数功能:NAND 长耗时操作看门狗直接喂狗弱钩子
* 入口参数:无
* 返回值:无
* 限定条件:任意上下文可调(内核启动前 / IWDG 未启动时为空操作)
* 函数说明:心跳钩子(nand_ftl_wd_beat)只能维持"心跳位",喂狗动作本身在
* defaultTask 主循环(task_wd_poll)——若长耗时 FTL 操作(GC/整卷
* 格式化)发生在 defaultTask 上下文,主循环被阻塞在 FTL 调用里,
* 喂狗点停摆 → 心跳位再新也无人喂 → IWDG 误复位(2026-10-02 台架
* 实证:console tx fault 条目落盘触发 GC,poller 饥饿 ~2 s → IWDG
* 复位、无任何 stall 日志)。本钩子让 FTL 长路径在操作进行中直接
* 喂狗,覆盖"喂狗点自身被长 I/O 阻塞"的形态。强符号由
* App/util/task_watchdog.c 提供(仅 IWDG 已启动时生效)。
*/
void nand_ftl_wd_feed(void);
#ifdef __cplusplus
}
#endif
+13
View File
@@ -8,6 +8,10 @@
* 2026-07-20 王建锋 创建初始版本
* 2026-09-21 E-31 resume 失败按错误分类:仅真空白判新卷,其余失败
* 返回 mount 层(禁止静默清 map 触发整卷重格式化)
* 2026-10-02 王建锋 resume 成功后增打 journal head/tail/epoch:复盘
* "复位后所有写入丢失"时 sectors used 不足以判定
* journal 回退(覆盖写不改 count),head/tail/epoch 是
* 唯一能暴露 resume 锚错 checkpoint 的证据
*/
/* 头文件包含区 */
@@ -245,6 +249,15 @@ DSTATUS disk_initialize(BYTE pdrv) {
} else {
DBG_INFO("Map resumed: %lu/%lu sectors used",
dhara_map_size(&s_map), dhara_map_capacity(&s_map));
/* journal 头/尾/epoch 一并打印:2026-10-02 台架复盘"复位后写入全部
* 丢失"时,只看 sectors used 判断不出 journal 是否回退(覆盖写场景
* count 不变),必须看 head/tail/epoch 才能发现 resume 锚错了
* checkpoint(详见 Lib/dhara/journal.c 的 2026-10-02 本地修复注释)。
* 纯内存字段、零 I/O,保留作长期可观测性。 */
DBG_INFO("Map head=%lu tail=%lu epoch=%u",
(unsigned long)s_map.journal.head,
(unsigned long)s_map.journal.tail,
(unsigned)s_map.journal.epoch);
}
}