From d1fb3579891685c7a996eb8fa6bf4b122d195e10 Mon Sep 17 00:00:00 2001 From: wangfq Date: Fri, 28 Aug 2026 09:15:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(vd960Loop):=20=E7=9C=8B=E9=97=A8=E7=8B=97?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E5=8F=8C=E4=BF=9D=E9=99=A9=E5=96=82=E7=8B=97?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=20+=20=E8=B6=85=E6=97=B6=E5=AF=B9=E9=BD=90?= =?UTF-8?q?=20V4B=EF=BC=881.64s=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对照 DLD154V4B V2.10(同款 AT32F421): - 原直喂模式缺 ISR 活性检测: TMR15 ISR 死但主循环活 -> 看门狗永不复位(假活) - 升级: TMR15 ISR 5ms 递增 g_wdg_counter + 主循环 poll_wdg() 500ms 才 reload - 超时 3s(div64/rld1875) -> 1.64s(div16枚举/rld4095) - wdt_feed 定义移至 TaskLoop.c 改名 poll_wdg, 与 V4B 同构 - 修正 main.c 注释矛盾(4687 vs 1875); 沿用 WDT_CLK_DIV_16 枚举写法避免 V4B 同源传值 bug - 隔离测试 3 项断言全过(分频16/超时1638ms>500ms/10s喂20次/ISR死不喂) --- vd960Loop/docs/devlog.md | 39 +++++++++++++++++++ .../at32f421_freertos_demo/inc/TaskLoop.h | 12 +++++- .../at32f421_freertos_demo/src/TaskLoop.c | 20 +++++++++- .../at32f421_freertos_demo/src/main.c | 25 ++++-------- 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/vd960Loop/docs/devlog.md b/vd960Loop/docs/devlog.md index 23661dc..941b9ea 100644 --- a/vd960Loop/docs/devlog.md +++ b/vd960Loop/docs/devlog.md @@ -4,6 +4,45 @@ --- +## 2026-08-28 — 看门狗升级:双保险喂狗模式 + 超时对齐 V4B(1.64s) + +### 背景 + +与 DLD154V4B(同款 AT32F421)看门狗实现对照后发现三个问题: + +| 问题 | 说明 | +|------|------| +| **直喂模式缺 ISR 活性检测** | 原实现主循环每 10ms 无条件 `wdt_feed()`——TMR15 ISR 死掉但主循环活着时,看门狗照样被喂,系统"假活"(时序状态机全停但永不复位) | +| **超时 3s 偏长** | `div=64, rld=1875` → 3s;V4B 已用 1.64s,复位自愈更快 | +| **注释矛盾** | `main.c` 注释写"重载值=4687 超时≈3秒"(4687 是 7.5s 的算法),实际 1875→3s | + +### 改动(对齐 DLD154V4B V2.10) + +```c +// TaskLoop.h +#define WDT_COUNTER_LIMIT 100 // 喂狗周期 500ms (TMR15 5ms × 100) +#define WDT_DIV 2 // IWDT 分频枚举值: 2 = WDT_CLK_DIV_16 (实际分频 16) +#define WDT_RLD 4095 // 12bit 重装载 → 超时 ≈ 1.64s +``` + +| 文件 | 变更 | +|------|------| +| `src/main.c` | `wdt_init()`:`WDT_CLK_DIV_64/1875` → `WDT_CLK_DIV_16/4095`(超时 3s→1.64s);`wdt_feed` 定义删除(移至 TaskLoop.c);注释修正 | +| `src/TaskLoop.c` | +`g_wdg_counter` + `poll_wdg()`(500ms 才 reload);TMR15 ISR 5ms 递增;调用点 `wdt_feed()`→`poll_wdg()` | +| `inc/TaskLoop.h` | +WDT 宏 + `poll_wdg` 声明 + `g_wdg_counter` extern(删 `wdt_feed`) | + +### 验证 + +- 隔离测试(host gcc mock 3bit 寄存器语义)3 项断言全过:分频 16/重载 4095/超时 1638ms > 500ms 喂狗周期、10s 喂狗 20 次(500ms 精确)、ISR 死不喂狗 +- 双保险语义:ISR 死 → 计数不涨 → 永不喂狗;主循环死 → poll_wdg 不执行 → 超时复位 +- 待现场验证:LSI 实际频率偏差对复位时间的影响 + +### ⚠ 踩坑提醒(V4B 同源事故) + +`wdt_divider_set()` 参数是**枚举值**不是分频数值(`WDT_CLK_DIV_16=0x02`,寄存器只取低 3 位)——V4B 曾把 `WDT_DIV=16` 当数值传入 → 实际分频 4 → 超时 410ms < 500ms 喂狗周期 → **不断复位重启**。本次 vd960Loop 直接沿用枚举写法,避免同坑。 + +--- + ## 2026-08-27 — LOOP_MEASURE_BASE 归一化基数上报(协议 V1.09) ### 背景 diff --git a/vd960Loop/utilities/at32f421_freertos_demo/inc/TaskLoop.h b/vd960Loop/utilities/at32f421_freertos_demo/inc/TaskLoop.h index 4e49385..398b2af 100644 --- a/vd960Loop/utilities/at32f421_freertos_demo/inc/TaskLoop.h +++ b/vd960Loop/utilities/at32f421_freertos_demo/inc/TaskLoop.h @@ -41,6 +41,15 @@ #define FREEZE_TIMEOUT 1000 // 冻结超时: ~10s @ 10ms/tick #define FREEZE_STABILITY_RATE 2 // 稳定性窗口: 参考值的 ±2% +/*=========================================================================== + * 看门狗 (IWDT) - 对齐 DLD154V4B V2.10 + * 双保险模式: TMR15 ISR 5ms 递增 g_wdg_counter, 主循环 poll_wdg() 每 500ms 喂狗 + * 超时 = WDT_DIV 枚举分频 x (WDT_RLD+1) / LSI(约40kHz) 约 1.64s + *===========================================================================*/ +#define WDT_COUNTER_LIMIT 100 // 喂狗周期 500ms (TMR15 5ms x 100) +#define WDT_DIV 2 // IWDT 分频枚举值: 2 = WDT_CLK_DIV_16 (实际分频 16; 勿传 16!) +#define WDT_RLD 4095 // 12bit 重装载 -> 超时约 1.64s + /*=========================================================================== * 离开检测: 1 = 平坦性三条件 (CN200910309382), 0 = cnt_release 防抖 *===========================================================================*/ @@ -228,7 +237,8 @@ uint8_t update_moving_average(uint32_t* p_sum, uint16_t* p_cnt, void set_loops_relay_on(uint8_t loop_num); void set_loops_relay_off(uint8_t loop_num); -void wdt_feed(void); +void poll_wdg(void); +extern volatile uint16_t g_wdg_counter; // 看门狗活性计数 (TMR15 5ms 递增) extern TaskHandle_t usart_task_handler; diff --git a/vd960Loop/utilities/at32f421_freertos_demo/src/TaskLoop.c b/vd960Loop/utilities/at32f421_freertos_demo/src/TaskLoop.c index 09f28c7..537152c 100644 --- a/vd960Loop/utilities/at32f421_freertos_demo/src/TaskLoop.c +++ b/vd960Loop/utilities/at32f421_freertos_demo/src/TaskLoop.c @@ -24,6 +24,7 @@ Loop154_States g_loop_states = {0}; uint32_t g_sys_freq = 0; uint8_t g_input_div = 1; uint32_t g_safe_max_cnt = LC_HOLD_TIME; +volatile uint16_t g_wdg_counter = 0; // 看门狗活性计数 (TMR15 ISR 5ms 递增) /*=========================================================================== * 一阶 IIR 低通滤波器(对齐 DLD154V4B) @@ -252,6 +253,9 @@ void TMR15_GLOBAL_IRQHandler(void) if (tmr_interrupt_flag_get(TMR15, TMR_OVF_FLAG) != RESET) { + /*--- 看门狗活性计数 (5ms) ---*/ + g_wdg_counter++; + /*--- 50ms tick 分频 ---*/ TM1cnt++; if (TM1cnt >= 10) { @@ -657,6 +661,20 @@ void vd1_task_per_channel(Loop154_Unit *unit) /*=========================================================================== * loop_task_function — FreeRTOS 主任务(对齐 DLD154V4B main 循环) +/*=========================================================================== + * 看门狗喂狗 (双保险, 对齐 DLD154V4B V2.10) + * TMR15 ISR 5ms 递增 g_wdg_counter; 计数达 100 (500ms) 才 reload + * ISR 死 -> 计数不涨 -> 永不喂狗; 主循环死 -> 本函数不执行 -> 超时复位 + *===========================================================================*/ +void poll_wdg(void) +{ + if (g_wdg_counter >= WDT_COUNTER_LIMIT) { // 100 x 5ms = 500ms + g_wdg_counter = 0; + wdt_counter_reload(); + } +} + +/*=========================================================================== * 10ms 周期,独立处理每路线圈。 *===========================================================================*/ void loop_task_function(void *pvParameters) @@ -705,7 +723,7 @@ void loop_task_function(void *pvParameters) } } - wdt_feed(); + poll_wdg(); vTaskDelay(10); // 10ms tick, M4 优化: 双路 IIR + 进入确认 + 斜率限幅 } } diff --git a/vd960Loop/utilities/at32f421_freertos_demo/src/main.c b/vd960Loop/utilities/at32f421_freertos_demo/src/main.c index e5da543..0fab920 100644 --- a/vd960Loop/utilities/at32f421_freertos_demo/src/main.c +++ b/vd960Loop/utilities/at32f421_freertos_demo/src/main.c @@ -59,9 +59,8 @@ __IO uint32_t TimingDelayDec; TaskHandle_t loop_task_handler; // 看门狗相关 -#define WDT_TIMEOUT_MS 3000 // 看门狗超时时间 3秒 +#define WDT_TIMEOUT_MS 1600 // 看门狗超时时间: IWDT div16 rld4095, LSI约40kHz -> ~1.64s void wdt_init(void); -void wdt_feed(void); tmr_output_config_type tmr_oc_init_structure; @@ -104,20 +103,19 @@ void InitPkgUart(Pkg_Uart * pkg){ * @param none * @retval none * @note 超时时间 = (预分频系数 × 重载值) / LSI频率 - * LSI频率约 40kHz,预分频64,重载值=4687,超时≈ 3秒 + * LSI频率约 40kHz,预分频16(枚举 WDT_CLK_DIV_16),重载值=4095,超时≈ 1.64秒 */ void wdt_init(void) { // 使能看门狗寄存器写访问 wdt_register_write_enable(TRUE); - // 设置预分频系数为 64 - wdt_divider_set(WDT_CLK_DIV_64); + // 设置预分频: 必须用枚举 WDT_CLK_DIV_16 (=0x02), 勿传数值 16! (V4B 踩坑) + wdt_divider_set(WDT_CLK_DIV_16); - // 设置重载值 - // 超时时间 = (64 × 4687) / 40000 ≈ 7.5秒 - // 如果需要 3秒: (64 × 1875) / 40000 = 3秒 - wdt_reload_value_set(1875); + // 设置重载值 4095 (12bit 最大) + // 超时时间 = (16 × 4096) / 40000 ≈ 1.64秒 + wdt_reload_value_set(4095); // 重载计数器 wdt_counter_reload(); @@ -128,15 +126,6 @@ void wdt_init(void) PRINT("Watchdog initialized, timeout: %d ms\n", WDT_TIMEOUT_MS); } -/** - * @brief 喂狗(重载看门狗计数器) - * @param none - * @retval none - */ -void wdt_feed(void) -{ - wdt_counter_reload(); -} uint16_t timer_period = 0; uint16_t channel1_pulse = 0;