ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

嵌入式可靠性设计:看门狗、保护机制与降级策略三层防线

嵌入式可靠性设计:看门狗、保护机制与降级策略三层防线 1. 从一次凌晨三点的复位说起可靠性设计的边界在哪设备半夜重启这件事做过量产的同行大概都遇到过。我第一次碰上比较典型的一次是一台装在户外的采集终端白天跑得好好的一到夜里气温降到零下就开始周期性重启有时候两小时一次有时候一整晚只有一次。现场日志什么都没有因为重启之后 RAM 全丢了日志还没落盘就断电了。当时的第一反应是电源问题换了更大容量的电容好了三天第四天又开始。后来才查出来是低温下晶振起振时间变长初始化阶段某个外设的等待循环没有超时保护卡死在 while 里看门狗把它拉回来了——从结果上看看门狗确实救了设备但设备一直在重启本质上仍然不可用。这件事让我对嵌入式可靠性有了一个比较清醒的认识看门狗、保护机制、降级策略这三样东西从来不是三个独立的模块而是一条完整的纵深防线。看门狗是最后一道闸门它管的是程序彻底跑飞之后还能不能回来保护机制管的是故障发生的第一时间能不能不烧硬件、不丢数据降级策略管的是核心功能受损之后设备还能不能以某种残缺但可用的形态继续提供服务。三者缺一个系统在实验室里都跑得很欢到了现场就开始出洋相。这篇内容想聊的就是这三层防线怎么落地。核心关键词围绕嵌入式、看门狗、保护机制、降级、工程可靠性展开面向的是已经能把板子点起来、能跑通业务逻辑但还没认真想过这东西坏了怎么办的开发者——包括做消费电子、工业控制、车载周边、电力采集、仪器仪表的同行。如果你正在写第一版量产固件或者手上的项目刚从能演示往能交付过渡这里面的东西大概率会用得上。我会尽量把每个选择背后的原因讲清楚而不是只给一串结论因为可靠性这件事最怕的就是照抄别人的参数抄错了自己也看不出来。先说一个贯穿全文的判断标准任何保护机制如果没法被验证那它约等于不存在。你以为自己加了看门狗实际上它可能永远不会触发你以为写了降级逻辑实际上它可能永远进不去那个分支。后面每一节我都会提到怎么证明它真的在工作这一点比代码本身更重要。2. 看门狗的本质它只能兜住一类故障别指望它兜住所有2.1 看门狗真正能检测的故障类型先把概念掰清楚。看门狗Watchdog的工作原理说白了就是一个递减计数器程序必须在计数器减到零之前把它重新装填一遍这个动作俗称喂狗。如果你没喂计数器溢出硬件产生复位信号CPU 重新从头开始跑。它检测的不是程序有没有出错而是程序有没有按时到达某个位置。这个区别非常关键。看门狗能兜住的故障本质上是执行流的失控死循环、野指针跳飞到非法区域、某个阻塞式等待卡死、任务调度器被饿死、中断风暴导致主循环拿不到时间片。这些情况下代码不会主动告诉你我挂了但喂狗动作会停止看门狗就会介入。看门狗兜不住的东西同样要列清楚逻辑错误但执行流正常比如温度计算用错了公式程序照常跑、照常喂狗输出永远是错的。这种只能靠单元测试和现场数据校验发现。内存数据被静默篡改某个 DMA 越界把关键变量冲掉了程序还在正常运行。这需要 CRC、ECC、MPU 之类的机制看门狗无能为力。硬件已经损坏MOS 击穿、传感器断路软件再怎么复位也没用。喂狗动作本身被污染这是最要命的一种后面单独讲。我见过不少项目的看门狗实际上是心理安慰型配置——超时时间设成 5 秒喂狗放在主循环最后一行看起来很规范。但只要主循环里任何一个函数卡住超过 5 秒比如某个慢速 Flash 擦除设备就复位。结果就是现场偶发重启还查不出原因。所以看门狗超时时间的计算必须基于最坏情况下两次喂狗之间的最大间隔而不是正常情况下大概多久跑一圈。2.2 独立看门狗、窗口看门狗和外部看门狗芯片怎么选以常见 ARM Cortex-M 系列 MCU 为例片内一般有两种看门狗独立看门狗IWDG和窗口看门狗WWDG。IWDG 通常挂在自己的低速内部 RC 振荡器上即使主时钟挂了、PLL 失锁了它照样计数独立性强WWDG 挂在 APB 总线上时钟来自系统时钟但它的特点是喂早了也算错——必须在一个时间窗口内喂狗喂太早和喂太晚都会复位。类型时钟源特点适用场景独立看门狗 IWDG独立低速 RC主时钟失效仍工作只能喂晚报错通用兜底绝大多数场景首选窗口看门狗 WWDGAPB 系统时钟喂太早/太晚都复位带早期预警中断对执行节拍有严格要求的控制环外部看门狗芯片芯片自身 RC完全独立于 MCU可断电复位、可控制电源安全等级要求高、MCU 可能整体死锁软件看门狗任务级系统滴答只能检测任务级饿死MCU 硬件死锁无效配合硬件看门狗使用做细粒度监控选型逻辑其实不复杂。MCU 可能整体死锁、或者你需要控制电源通断的场景加外部看门狗芯片因为它通过一个 GPIO 或者专用的 WDI 引脚接收喂狗脉冲MCU 完全没反应时它会拉低复位脚甚至可以配合电源开关把整机断电再上电。普通场景用 IWDG 就够了它的独立性已经能满足大部分要求。WWDG 适合用在必须按固定节拍执行的场合比如电机的电流环、某些实时性要求极高的采样任务——如果程序跑飞之后恰好在附近疯狂喂狗IWDG 拦不住WWDG 能拦住因为喂早了也会复位。这里有个细节值得说IWDG 和 WWDG 最好不要二选一而是两个都开。让 WWDG 监控高频关键任务IWDG 监控整个系统的活性。两者超时时间拉开差距比如 WWDG 设 20msIWDG 设 500ms。这样一旦是局部任务出问题先由 WWDG 报警WWDG 有早期唤醒中断 EWI可以在复位前先记录现场实在不行再由 IWDG 兜底。多花的那点代码换来的是排障时能区分是哪一层先撑不住的。2.3 喂狗位置的选择为什么我坚持不在中断里喂狗这是踩坑最多的地方。先说结论喂狗动作必须放在有明确业务含义的代码路径上绝不要放在定时器中断里无脑喂。原因很简单。中断的优先级通常高于主循环即使主循环卡死在一个 while 里定时器中断照样触发照样喂狗看门狗永远不触发。这种情况下设备表面上看活着——灯还在闪、中断还在跑但业务逻辑已经停了。用户看到的是设备亮着但不干活比直接重启还难排查。我遇到过一台设备现场表现是屏幕正常刷新但按键无响应查了两天才发现喂狗在 SysTick 中断里主任务早就死在某个 I2C 等待上了。比较靠谱的做法是心跳汇聚 集中喂狗/* 每个关键任务周期性地置位自己的心跳标志 */ #define TASK_SENSOR (1u 0) #define TASK_COMM (1u 1) #define TASK_CONTROL (1u 2) #define TASK_STORAGE (1u 3) static volatile uint32_t g_heartbeat 0; void sensor_task(void) { /* ... 业务处理 ... */ g_heartbeat | TASK_SENSOR; } void comm_task(void) { /* ... 业务处理 ... */ g_heartbeat | TASK_COMM; } /* 看门狗任务只有所有任务都上报过心跳才喂狗 */ void wdg_task(void) { const uint32_t all TASK_SENSOR | TASK_COMM | TASK_CONTROL | TASK_STORAGE; if ((g_heartbeat all) all) { g_heartbeat 0; /* 清标志进入下一轮 */ HAL_IWDG_Refresh(hiwdg); } /* 不满足条件就不喂安静地等看门狗动手 */ }这个模式的好处是任何一个任务卡住看门狗都不会被喂设备会复位而不是带着一个半死的状态继续跑。g_heartbeat的读写要注意原子性单核 MCU 上 32 位对齐变量的读改写如果是读-或-写三步理论上会被中断打断稳妥的做法是用__disable_irq()包一下或者干脆给每个任务分配一个独立的volatile uint8_t标志避开位操作。还有一个坑调试时断点会触发看门狗。这个好解决MCU 一般有调试冻结位DBGMCU 里的 IWDG 停止位调试时让看门狗暂停计数。但千万别忘了在发布版本里把这段调试代码排除掉我就见过有人留着#ifdef DEBUG里的一段调试期间关看门狗结果发布固件的宏没切干净量产设备的看门狗是关着的跑了半年才发现。3. 保护机制要分层硬件先兜底软件再兜底最后才是看门狗3.1 硬件保护层过流、过压、欠压与热保护看门狗是最后一道门它前面必须有人。硬件保护层的第一原则是响应速度要快于软件——软件一个采样周期可能 1ms硬件保护响应是微秒级短路这种事故根本等不到软件反应过来。常见的几层硬件保护电源入口TVS 管吸收浪涌自恢复保险丝PPTC限制持续过流共模电感抑制共模干扰。这部分主要是防外部环境成本不高但效果明显。负载回路分流电阻 比较器做硬件过流比较一旦超阈值直接关断 MOS 的栅极驱动不走 MCU。或者用带过流保护的负载开关芯片把阈值设在额定电流的 1.5 到 2 倍。温度NTC 热敏电阻或者数字温度传感器如常见 I2C 接口的那类关键的功率器件最好贴一个因为环境温度传感器测不到芯片自己的结温。电压监控专用的电源监控芯片或者 MCU 自带的掉电检测PVD。欠压比过压更阴险因为 MCU 在 2.0V 到 2.4V 之间可能会执行乱码指令、误写 Flash这种损坏是不可逆的。我的习惯是凡是能烧掉的路径都要有硬件级的断路能力。软件过流保护作为第二道可以做得更精细比如根据温度动态调整阈值但不能是唯一的一道。3.2 软件保护层参数校验、栈保护与内存保护单元软件层的保护重点不在防止故障发生而在防止故障扩散。几件必做的事入参校验尤其是来自外部通信和传感器的数据。通信收到的长度字段、索引、地址全部要校验范围传感器读数要做合理性检查比如温度传感器突然报 300℃大概率是通信出错而不是真的着火了。这里的原则是不信任任何外部输入包括看起来是自己人的上位机。栈溢出检测。栈溢出是嵌入式最难查的一类问题之一因为症状千奇百怪。两种常用手段一是栈哨兵在栈顶和栈尾填魔数周期性检查是否被改写二是编译期的-fstack-usage生成栈使用报告静态分析最大栈深度。任务栈大小不要拍脑袋定用uxTaskGetStackHighWaterMark之类的接口看水印。#define STACK_CANARY 0xDEADBEEFUL #define STACK_WORDS 256 static uint32_t s_stack[STACK_WORDS]; void stack_guard_init(void) { s_stack[0] STACK_CANARY; s_stack[STACK_WORDS - 1] STACK_CANARY; } /* 周期性调用发现哨兵被改写立即降级或复位 */ int stack_guard_check(void) { if (s_stack[0] ! STACK_CANARY || s_stack[STACK_WORDS - 1] ! STACK_CANARY) { return -1; } return 0; }MPU内存保护单元。带 MPU 的 MCUCortex-M3/M4/M7 大部分都有一定要用起来。典型配置是把 Flash、RAM 划成几个区域给只读数据加写保护给栈加越界保护给不该被执行的数据区加执行禁止XN。收益很直接野指针写入只读区、栈溢出踩到相邻区域会在发生的瞬间触发 MemManage 异常而不是等到几秒钟后系统莫名其妙挂掉。有了 MPU配上一个 MemManage 故障处理函数记录出错地址排障效率完全不是一个量级。断言。assert在开发阶段全开发布版本可以选择保留一部分关键断言尤其是与安全相关的触发时不直接死机而是走降级流程并记录故障码。很多团队把断言全关掉理由是发布版本不能因为断言重启但正确的做法是让断言触发降级而不是重启。3.3 Flash 与通信数据的完整性保护存储和通信这两块数据是被静默篡改的重灾区必须靠校验来兜底。Flash 里的关键配置、标定参数建议双备份 CRC。写入顺序是先擦 B 区 → 写 B 区 → 校验 B 区 → 更新区头标志A 区在 B 区写成功之前一直保留。读取时优先读标志位有效且 CRC 通过的那一份两份都坏就用出厂默认值并进入降级状态。这个思路叫影子备份实现成本很低但能扛住掉电时刻的写入中断。通信数据同理。串口、CAN、I2C 都有自己的校验机制CAN 有 CRC串口可以加校验和但应用层协议最好再加一层自己的包校验因为硬件校验只能保证传输没错不能保证对端发的就是对的。我一般会在协议头放一个魔数、长度、序号和整包 CRC16收包流程严格按找头 → 校验长度 → 校验 CRC → 处理四步走任何一步不过就丢包并计数。传感器数据还要加一层变化率限制。真实的物理量不会凭空跳变温度、压力、电流都有惯性。如果两次采样的差值超过物理上可能的范围就把这次采样标记为可疑连续多次可疑就判定该传感器失效切到降级策略用冗余传感器、用历史值保持、或者用默认值。4. 降级不是关功能分级策略与状态机设计4.1 先把失效模式列清楚再谈降级动作降级这件事很多人是反着做的——先想我能关掉什么功能再去找触发条件。正确的顺序是反过来先枚举失效模式再定义每种模式下的可用功能集合。一个简化但实用的做法是列一张表左边是失效模式右边是检测手段、降级动作、恢复条件。以一台带通信、传感、显示、存储的采集终端为例失效模式检测手段降级动作恢复条件主通信链路中断连续 N 次心跳超时切本地缓存模式数据先存后传心跳恢复正常且持续 30s主传感器失效超量程或变化率异常切冗余传感器无冗余则用默认值连续 10 次采样在合理范围存储写失败写入返回错误或校验失败切只读模式保留最新数据在 RAM擦除重试成功输入电压偏低PVD 或 ADC 检测关背光、降采样率、降主频电压回到正常区间且持续 60s芯片温度过高内部温度传感器降功率输出必要时暂停充电温度回落 10℃ 以上这张表本身没什么技术含量价值在于逼着团队把哪种情况算失效讨论清楚。我见过一个项目传感器断线的判定阈值是连续 3 次读数为 0结果某次环境温度真的是 0℃设备直接进降级了。阈值定得太粗降级就成了误报来源。另外要明确一个概念降级不等于失控。降级状态下核心安全功能必须保留。比如一台设备通信全断、显示全灭但过温保护、过流保护必须照常工作。所以在设计降级策略时我会把所有功能分成三档安全相关永不关闭、核心功能尽量保留可降精度降频率、体验功能可以关。降级只允许动第二档和第三档。4.2 滞回与去抖让降级状态不来回抖降级逻辑写完最容易出的问题是状态抖动。比如温度 85℃ 触发降功率降到 84.9℃ 又恢复功率一恢复温度又上去如此反复一分钟内切换几十次。这种抖动对硬件是折磨——继电器咔咔响、MOS 反复开关寿命直接打折。解决办法就是滞回 持续时间判定进入降级的阈值和退出降级的阈值必须不同中间留一段缓冲。比如 85℃ 进入75℃ 才退出中间 10℃ 是死区。无论进入还是退出都要连续满足条件一段时间才真正切换比如连续 20 次采样都超阈值。切换次数做限制一段时间内切换超过 N 次就锁定在降级状态只允许人工复位。写成状态机比较清晰typedef enum { ST_NORMAL 0, ST_WARN, ST_DEGRADED, ST_FAILSAFE } sys_state_t; /* 阈值超温进降级 85回落到 75 才退出去抖 20 次采样 */ #define TEMP_ENTER_C 85 #define TEMP_EXIT_C 75 #define DEBOUNCE_CNT 20 static sys_state_t s_state ST_NORMAL; static uint16_t s_enter_cnt 0; static uint16_t s_exit_cnt 0; void temp_state_machine(int16_t temp_c) { switch (s_state) { case ST_NORMAL: if (temp_c TEMP_ENTER_C) { if (s_enter_cnt DEBOUNCE_CNT) { s_enter_cnt 0; s_state ST_DEGRADED; apply_degrade(); /* 降功率、降采样率 */ log_fault(FAULT_OVERTEMP); } } else { s_enter_cnt 0; } break; case ST_DEGRADED: if (temp_c TEMP_EXIT_C) { if (s_exit_cnt DEBOUNCE_CNT) { s_exit_cnt 0; s_state ST_NORMAL; apply_recover(); log_fault(FAULT_RECOVERED); } } else { s_exit_cnt 0; } break; default: break; } }这段代码没什么高深的地方但每一处延时和滞回都有明确目的DEBOUNCE_CNT防瞬时干扰滞回窗口防边界抖动log_fault保证状态切换可追溯。实际项目里建议再加一个切换次数上限防止极端情况下反复进出。4.3 降级必须可观测、可恢复两个最容易被忽略的点。可观测降级发生了必须留下痕迹。至少要有三样东西——故障码存在非易失存储里掉电不丢、降级持续时间、触发时的关键快照温度、电压、当时的任务栈水印。没有这些现场返回的设备你根本不知道它经历过什么。我习惯在备份 RAM 或者后备寄存器里维护一个环形缓冲区记录最近 20 条事件包括复位、降级、恢复、通信错误峰值。设备一回来把这段 dump 出来故障基本就定位了。可恢复降级不能是单行道。除了真正不可逆的故障比如硬件损坏、Flash 擦写寿命耗尽绝大多数降级都应该有自动恢复路径。恢复逻辑要注意两点一是恢复条件要比进入条件苛刻也就是上面说的滞回二是恢复要分步不要一次性把功能全开回来比如先恢复采样率稳定一分钟后再恢复通信上报再稳定一分钟才恢复背光和高速率。一步一停避免恢复瞬间又把系统压垮。还有一个经验降级状态要不要上报取决于场景。工业设备降级通常要立即告警因为运维人员需要知道设备带病运行消费类产品降级往往不告警只是悄悄降低体验避免用户恐慌。这个是产品决策不是技术决策但做软件的人要主动提出来。5. 现场复位排查实录从复位原因寄存器到备份寄存器5.1 复位原因寄存器能告诉你什么设备从现场回来说老是重启这是最常见的故障描述。第一步永远是读复位原因寄存器。以 STM32 为例RCC_CSR 里有一组标志位能区分上电复位、掉电复位、软件复位、独立看门狗复位、窗口看门狗复位、低功耗模式复位、引脚复位。void dump_reset_cause(void) { uint32_t csr RCC-CSR; if (csr RCC_CSR_LPWRRSTF) log_fault(FAULT_RESET_LOWPOWER); if (csr RCC_CSR_WWDGRSTF) log_fault(FAULT_RESET_WWDG); if (csr RCC_CSR_IWDGRSTF) log_fault(FAULT_RESET_IWDG); if (csr RCC_CSR_SFTRSTF) log_fault(FAULT_RESET_SOFT); if (csr RCC_CSR_PORRSTF) log_fault(FAULT_RESET_POWERON); if (csr RCC_CSR_PINRSTF) log_fault(FAULT_RESET_PIN); if (csr RCC_CSR_BORRSTF) log_fault(FAULT_RESET_BROWNOUT); __HAL_RCC_CLEAR_RESET_FLAGS(); /* 读完立刻清避免下次误判 */ }这段代码建议放在main里最靠前的位置而且一定要先读完再清标志。很多人习惯在 HAL 初始化的某个环节顺手清了标志结果自己的代码再去读全是零什么都查不到。看到 IWDGRSTF 就要往执行流卡死方向查哪个任务拿不到时间片、哪个阻塞调用没有超时、哪个中断被关了太久。看到 BORRSTF 就要往电源方向查带载能力够不够、大电流瞬间有没有跌落、电池内阻是不是老化了。看到 PINRSTF 就要查外部复位电路NRST 上的电容是不是太大导致上电复位延迟、有没有干扰耦合进来。5.2 把死亡现场留在备份 SRAM 里复位原因寄存器只能告诉你怎么死的告诉不了你死在哪。这时候需要备份 RAMBackup SRAM或者 RTC 备份寄存器这些区域在主电源掉电后由纽扣电池或超级电容供电内容不会丢。我的做法是在 RAM 里维护一个上次运行状态快照结构体包含当前任务 ID、当前状态机状态、最近一次喂狗时间戳、关键变量副本每隔一段时间比如 100ms把它同步到备份 SRAM 里。看门狗复位后启动时先读备份 SRAM把快照打印出来。typedef struct { uint32_t magic; /* 0x5A5A1234 表示快照有效 */ uint32_t last_task_id; uint32_t last_state; uint32_t last_feed_ms; uint32_t fault_code; uint32_t crc; } crash_snapshot_t; void snapshot_save(const crash_snapshot_t *s) { /* 写入备份 SRAM注意先写数据后写 magic保证原子性 */ memcpy((void *)BKPSRAM_BASE, s, sizeof(*s)); }这里有个顺序问题先写数据最后写 magic。如果写到一半断电magic 还是旧的下次启动就能识别出这份快照不完整避免拿一份残缺数据去误导排查。加了 CRC 更稳妥。有了这个机制本来需要复现两三天的偶发复位往往一次现场返回就能定位。我在一个项目里靠它查出了一次由 I2C 总线被从机拉死导致的主任务阻塞——快照里last_task_id永远停在通信任务上last_feed_ms距离复位时刻差了整整 800ms和看门狗超时时间吻合。没有快照这个结论很难拿到。5.3 几条容易误判的线索排查复位问题有几条经验值得记下来。看门狗复位不等于看门狗有问题。看门狗触发是结果不是原因真正的原因在它前面。急着去调看门狗超时时间只会把问题掩盖得更深。上电复位和掉电复位容易混淆。如果设备供电不稳掉电复位会频繁出现但看起来像上电重启。这时候要在 BOR 阈值和电源设计上找原因而不是查代码。软件复位要留人。NVIC_SystemReset()调用处最好加日志不然现场看到 SFTRSTF 完全不知道是谁触发的。有些初始化失败的处理逻辑会主动软复位撞上偶发故障就会形成复位-初始化失败-复位的死循环表现是设备反复重启。这种死循环特别隐蔽因为每次复位原因都是软件复位看起来人畜无害。中断里不要做长耗时操作。曾经有个项目串口中断里直接做协议解析和 Flash 写入正常情况没问题一旦数据量大就长时间关中断导致 SysTick 丢拍系统节拍紊乱最后表现为随机的任务超时和看门狗复位。中断服务函数的原则是快进快出把耗时工作挪到任务里。6. 怎么证明保护机制真的有效故障注入与老化验证6.1 主动制造故障从拉低总线到注入错误数据前面说了没验证过的保护机制约等于不存在。验证的基本手段是故障注入也就是主动把系统往坏里搞看它是否按预期响应。一份我常用的注入清单电源类用可编程电源缓慢下调电压看 PVD 是否在设定阈值触发、是否走了降级而不是直接死机快速上下电 100 次看是否会出现半启动状态。通信类用镊子或跳线把 I2C 的 SCL 拉低模拟总线被从机拉死看是否有超时恢复机制给串口发送错误 CRC 的包看是否正确丢弃并计数。传感器类拔掉传感器看是否检测到断线并切冗余用信号源注入超量程信号看是否判定失效。存储类在写入过程中强制断电重新上电看是否能从备份区恢复人为破坏 Flash 中的配置 CRC看是否回落到出厂默认值并进入降级。执行流类在任务里临时插入一个while(1)看门狗是否在预期时间内复位把喂狗函数临时注释掉看是否触发 IWDG 复位。每次注入都要记录三件事预期行为、实际行为、恢复时间。实际行为不符合预期就说明保护逻辑有缺口。我印象比较深的一次是注入了传感器断线结果系统直接死机而不是降级——查下去发现传感器读取函数里有个while等待标志位没有超时。这就是典型的保护机制里自己藏着死循环故障注入一下就暴露了。6.2 看门狗自身的验证看门狗本身也要验证而且要有专门的方法。第一验证它能复位。最简单的方式是固件里加一个隐藏命令触发后进入死循环不喂狗看设备是否在超时时间加复位时间之后重新启动。注意复位时间——很多 MCU 的看门狗复位不是瞬间的内部有个复位延时测量实际复位时间要和手册对得上。第二验证喂狗时机。如果是窗口看门狗要在窗口外喂一次确认它会复位。这个测试不做你根本不知道窗口配置对不对。第三验证复位后的恢复。看门狗复位后外设状态、通信连接、存储状态是否都能正确重建我见过设备看门狗复位后串口卡在错误状态需要重新插拔才能恢复通信的案例。看门狗把系统救回来了结果串口没救回来等于白救。第四长时间拷机时记录复位次数。用复位原因寄存器和备份 RAM 统计一段时间内的复位次数和类型如果 IWDG 复位次数不为零说明系统本身还有隐患不能算通过。6.3 上线前的那张检查清单最后把上面这些收拢成一张清单我在每个项目发布前都会过一遍。不敢说覆盖全部但能挡掉大部分低级问题。检查项通过标准看门狗已使能且不可被软件关闭发布固件里没有关闭看门狗的代码路径喂狗位置在业务路径上全部关键任务上报心跳后才喂狗看门狗超时时间基于最坏情况计算有书面计算过程包含最长阻塞时间复位原因在启动时被读取并记录有故障码和备份快照MPU 或栈哨兵已启用越界访问能在发生时刻被发现关键存储数据有双备份和 CRC掉电注入测试通过每种失效模式都有对应降级动作有失效模式与降级动作对照表降级状态可观测可恢复故障码、持续时间、快照齐全降级切换有滞回和去抖边界条件测试无抖动故障注入测试已执行有测试记录和实际行为对照我个人在实操中的体会是可靠性这块最难的从来不是技术本身而是在项目周期里给它留出时间。业务功能做完老板问什么时候能发版你说我还要做故障注入和拷机这话很难说出口。但真正上线之后每一次现场复位消耗的时间都远超当初做验证的时间。宁可前期多花一周也别在三个月后被半夜的电话叫起来查日志。还有一个可以马上落地的小习惯从现在开始把每一次复位原因都记下来写进非易失存储哪怕只是一个计数器。三个月后你手里就有一份真实世界的故障分布数据比任何手册都管用。
返回列表