首页 / 资讯中心 / 文章详情

样章-第10讲-看门狗异常恢复与卡机排查方法论

样章-第10讲-看门狗异常恢复与卡机排查方法论 ★ FEATURED ARTICLE
第 10 讲 | 看门狗、异常恢复与卡机排查方法论【本讲要点】设备卡机是量产后最贵的 bug——它不报错、不复现、还挑现场。这一讲给你一套从看门狗设计到复位原因回溯的完整方法。一、一个真实的卡机案例现象描述来自现场工单“按下紧急求助按键后设备偶尔就没反应了灯也不闪、按键也不响应。断电重启才恢复。”关键词“偶尔”、“没反应”、“重启恢复”。这类问题最折磨人因为它不复现实验室按 100 次可能一次都不出无日志卡住的时候设备已经死了什么都打不出来归因难用户说按了按键就这样但按键可能只是触发条件不是原因。这一讲就按这个案例把排查路径完整走一遍。二、卡机的四类根因先把卡机拆开。设备没反应只有四种可能类型现象典型成因死循环CPU 满载中断还能进while(!flag);等一个永远不来的标志死锁任务互相等待两个任务交叉拿锁在临界区里等信号量HardFault直接进异常处理空指针、栈溢出、非对齐访问中断风暴主循环永远得不到执行中断太频繁且没清标志 → 反复触发排查第一步永远是先确定属于哪一类。怎么区分看喂狗如果看门狗没复位说明系统还在活着可能是死锁或某个任务卡住如果看门狗复位了说明确实是死循环或 HardFault忙等也会停止喂狗接调试器打断看 PC 停在哪、哪个任务在跑——这是最快的定位方式。三、看门狗设计谁喂、在哪喂看门狗Watchdog是量产设备的最后一道保险。但用错了它就成了随机重启机。3.1 两个最常见的错误错误 1在一个高优先级任务里喂狗/* 危险只要这个任务活着其他任务全死了也不复位 */voidled_task(void*arg){for(;;){toggle_led();iwdg_feed();/* 只看这一个任务等于没看 */vTaskDelay(pdMS_TO_TICKS(500));}}错误 2在中断里喂狗/* 更危险只要系统 tick 还在跑狗就永远不咬 */voidSysTick_Handler(void){iwdg_feed();/* 完全失去意义 */}看门狗要能发现任务卡死就必须由所有关键任务的健康状态共同决定。3.2 正确的喂狗健康标志位/* 每个关键任务定期置自己的位只有全部置位才喂狗 */#defineHB_SAMPLE(1u0)#defineHB_PUBLISH(1u1)#defineHB_FSM(1u2)#defineHB_ALL(HB_SAMPLE|HB_PUBLISH|HB_FSM)staticvolatileuint32_ts_heartbeat0;/* 各任务到达自己的循环末尾就置位 */voidhb_report(uint32_tbit){taskENTER_CRITICAL();s_heartbeat|bit;taskEXIT_CRITICAL();}/* 监护任务只有所有位都置齐了才喂狗并清位 */voidwdg_task(void*arg){for(;;){vTaskDelay(pdMS_TO_TICKS(3000));/* 看门狗超时要 这个值 */if(s_heartbeatHB_ALL){iwdg_feed();s_heartbeat0;/* 清位下一轮重新累积 */}else{log_warn(hb missing: 0x%x,s_heartbeat);/* 不喂狗 → 让看门狗复位 */}}}这样设计的价值任何一个关键任务卡死标志位凑不齐看门狗必复位复位前还能打印出缺哪一个——hb missing: 0x2直接告诉你 publish 任务挂了。这是本讲最重要的一段代码。3.3 看门狗超时怎么定窗口说明太短正常的长耗时操作如 OTA 写 Flash会被误复位太长卡死后要等很久才恢复影响体验经验值超时时间是最长正常业务周期的 23 倍。如果最慢的任务 3 秒转一圈看门狗设 810 秒。特殊场景OTA 写入、大批量 Flash 擦除这类必然长耗时的操作要么在期间主动喂狗要么临时切换到窗口看门狗或延长超时。四、HardFault 现场还原如果卡机是 HardFault 引起的必须把现场冻结下来。Cortex-M 的异常进入会自动压栈我们可以把它取出来。/* 取自 FreeRTOS/裸机的通用 HardFault 处理 */__attribute__((naked))voidHardFault_Handler(void){__asmvolatile(tst lr, #4 \nite eq \nmrseq r0, msp \nmrsne r0, psp \nb hardfault_dump \n);}voidhardfault_dump(uint32_t*sp){/* 压栈顺序R0, R1, R2, R3, R12, LR, PC, xPSR */uint32_tr0sp[0];uint32_tr1sp[1];uint32_tr2sp[2];uint32_tr3sp[3];uint32_tr12sp[4];uint32_tlrsp[5];uint32_tpcsp[6];/* ← 出事的那条指令地址 */uint32_tpsrsp[7];/* 用 RTT 输出此时串口可能已不可靠 */SEGGER_RTT_printf(0,\r\n[HardFault]\r\nR0 %08x R1 %08x R2 %08x R3 %08x\r\nR12%08x LR %08x PC %08x PSR%08x\r\n,r0,r1,r2,r3,r12,lr,pc,psr);/* 把 PC 丢进 map 文件就能定位到具体函数和行 */for(;;);/* 停在原地等看门狗复位 或 调试器接管 */}关键用法记下PC的值打开编译生成的.map文件搜索这个地址落在哪个函数区间结合反汇编就能定位到具体哪一行出的问题。这套方法把随机死机变成了可定位的崩溃点。五、复位原因判断开机第一件事每次上电/复位第一件事应该是读取复位原因并记下来。typedefenum{RST_POWER_ON,/* 上电复位 */RST_WATCHDOG,/* 看门狗复位 ← 卡机的证据 */RST_SOFTWARE,/* 软件主动复位 */RST_PIN,/* 复位引脚 */RST_BROWNOUT,/* 掉电/欠压 */RST_UNKNOWN,}reset_cause_t;staticreset_cause_ts_boot_cause;voidboot_read_reset_cause(void){if(rcu_flag_get(RCU_FLAG_FWDGTRST)){/* 看门狗 */s_boot_causeRST_WATCHDOG;}elseif(rcu_flag_get(RCU_FLAG_SWRST)){/* 软件复位 */s_boot_causeRST_SOFTWARE;}elseif(rcu_flag_get(RCU_FLAG_PORRST)){/* 上电 */s_boot_causeRST_POWER_ON;}elseif(rcu_flag_get(RCU_FLAG_EPRST)){/* 引脚 */s_boot_causeRST_PIN;}else{s_boot_causeRST_UNKNOWN;}rcu_all_reset_flag_clear();/* 清标志下次才能测准 */}这个值要落到 Flash 里、要随上报数据一起传上去/* 每次启动记录一次量产设备靠这个统计卡机率 */nvm_write_u8(NVM_KEY_LAST_RESET,s_boot_cause);log_info(boot cause %d,s_boot_cause);价值如果现场统计发现 30% 的启动都是RST_WATCHDOG说明卡机是系统性问题必须查如果全是RST_POWER_ON说明设备其实很健康问题在别处。六、回到案例SOS 按键卡机有了上面的工具我们回头看那个案例。第一步判断类型在现场版本的固件里加上复位原因统计跑一周后RST_WATCHDOG占比明显偏高且都发生在求助按键被按之后。结论不是死锁是某个任务卡死导致喂狗失败。范围立刻缩小。第二步看健康位因为有hb missing日志复位前的最后一条日志是hb missing: 0x6 (HB_PUBLISH | HB_FSM 缺位 → 通信任务没转圈)指向通信/上报任务卡住了。第三步定位代码检查求助功能与通信任务的交互/* 问题代码简化 */voidsos_key_isr(void){g_sos_pending1;}voidpublish_task(void*arg){for(;;){if(g_sos_pending){g_sos_pending0;sos_send_immediately();/* ← 内部有一个同步等 ACK 的循环 */continue;/* ← 跳过了 hb_report() */}/* 正常上报 */...hb_report(HB_PUBLISH);}}问题找到了sos_send_immediately()里有一个等待 ACK的同步循环在弱网下会阻塞很久这就是偶尔的原因——网络好的时候不卡更致命的是走 SOS 分支时用了continue跳过了hb_report(HB_PUBLISH)健康位永远凑不齐 → 看门狗复位。两个 bug 叠在一起一个是阻塞一个是漏报心跳。第四步修复voidpublish_task(void*arg){for(;;){/* 1. SOS 改成插队而不是阻塞立即发送 */if(g_sos_pending){g_sos_pending0;sos_enqueue();/* 投递到高优先级队列不阻塞 */}/* 2. 无论走哪个分支都要报心跳 */process_normal();hb_report(HB_PUBLISH);}}修复后SOS 上报走独立的高优先级通道且不再阻塞主上报循环心跳必定上报。这就是看门狗 健康位 复位原因三件套的价值——它把偶尔卡机变成了可观测、可定位、可证伪的工程问题。七、可靠性工具箱可直接落地看门狗多任务健康位汇总喂狗缺位则复位并记录缺哪一位HardFault 处理压栈现场 RTT 输出PC配合 map 文件定位复位原因统计开机读取 落 Flash 随上报上传任务栈水位监视第 3 讲讲过防栈溢出堆水位监视防内存耗尽关键路径日志落 Flash卡机前最后几条日志是最宝贵的线索八、小结四句话1. 卡机只有四类根因先用看门狗是否复位把范围砍一半。2. 看门狗不能在一个任务里喂必须由所有关键任务的健康位共同决定。3. HardFault 要保存现场PC map 文件是定位崩溃点的标准姿势。4. 复位原因必须记录并上传——这是判断卡机是系统性问题还是偶发的唯一依据。至此 Part 4 结束。下一讲第 11 讲进入 Part 5我们从零实现一个Modbus RTU 从机讲清寄存器映射、帧解析和主从通信的真实调试过程。
阅读完成 · 觉得有帮助?
咨询建站