3、看门狗与复位:启动的第一道关卡
各位工程师,咱们接着聊。上一章我们把时钟树理清了,但时钟配置得再好,如果复位和看门狗没处理好,启动照样会翻车。这一章,我们就来啃下这两个硬骨头。
说实话,我在刚接触C2000那会儿,觉得看门狗就是个“定时炸弹”,动不动就复位,烦得很。后来才明白,不是它烦,是我没搞懂它的脾气。你想想看,一个系统跑在工业现场,电磁干扰、电源波动、程序跑飞,这些都是家常便饭。没有看门狗,芯片挂了都没人知道。
3.1 看门狗定时器:系统的“心跳监护仪”
看门狗定时器(WDT)说白了就是一个递减计数器。它不停地从某个初始值往下数,数到0就触发复位。你的任务就是在它数到0之前,给它“喂狗”——也就是重新装载计数值。
为什么叫“喂狗”?我习惯这么理解:狗饿了就会叫(复位),你按时喂它(清看门狗),它就乖乖的。你要是忙忘了,它就咬你一口(系统复位)。
核心要点:看门狗不是用来“防止”复位的,而是用来“检测”系统是否还在正常运行的。正常运行时,你会定期清狗;如果程序卡死或跑飞,没人清狗,系统就会自动复位,把控制权拉回来。
C2000的看门狗有几个关键寄存器,我列个表,大家对照着看:
| 寄存器 | 功能 | 我踩过的坑 |
|---|---|---|
| WDCNTR | 看门狗计数器,递减 | 读它的时候要注意,读操作本身不会影响计数值 |
| WDKEY | 喂狗寄存器,写入特定序列 | 必须按0x55→0xAA的顺序写,顺序错了直接复位 |
| WDCR | 控制寄存器,配置分频和模式 | 修改WDCR前,要先解锁,否则写不进去 |
| WDFLAG | 看门狗复位标志位 | 启动时一定要检查这个位,判断上次复位是不是看门狗干的 |
喂狗的正确姿势:我个人习惯在main函数的主循环里喂狗,而不是在中断里。为什么?因为如果中断还能响应,说明CPU至少没完全死掉,但主循环可能已经卡住了。在主循环喂狗,能更真实地反映系统状态。
3.2 复位源分析:到底是谁动了我的芯片?
系统启动时,第一件事就是搞清楚:这次复位是谁引起的?C2000主要有三个复位源:POR、XRS和WDRST。我一个个说。
3.2.1 POR:上电复位
POR(Power-On Reset)是芯片上电时自动产生的复位。它是最彻底的复位,所有寄存器都会回到默认值。我记得有一次调试,发现芯片上电后某些外设配置没生效,查了半天,原来是POR后时钟默认是内部振荡器,而我以为它用的是外部晶振。
POR的特点:
- 发生在VDD上升到阈值电压时
- 复位所有寄存器到默认状态
- 复位持续时间由内部定时器决定,约几个毫秒
- 启动后必须重新配置时钟和所有外设
3.2.2 XRS:外部复位
XRS引脚是外部复位输入,低电平有效。你可以在XRS引脚上接一个按键,或者接一个外部复位监控芯片。当XRS被拉低时,芯片立即复位。
这里有个细节要注意:XRS引脚是双向的。它不仅能接收外部复位信号,还能输出内部复位状态。也就是说,当看门狗复位发生时,XRS引脚也会被拉低,告诉外部设备“芯片复位了”。
曾经踩过的坑:我在一个项目里,把XRS引脚直接连到了外部复位芯片的输出上。结果发现,看门狗复位时,XRS被拉低,外部复位芯片检测到低电平,以为是自己触发了复位,也跟着输出复位信号。两个复位源互相干扰,系统反复重启。后来我在XRS引脚上加了一个隔离电阻才解决。
3.2.3 WDRST:看门狗复位
WDRST是看门狗定时器溢出产生的复位。它和POR、XRS最大的区别是:WDRST不会复位所有寄存器。有些寄存器在WDRST后仍然保持原来的值,比如某些外设的控制寄存器。
为什么会这样?TI的设计意图是:看门狗复位通常是因为程序跑飞,但外设的配置可能是正确的。如果全部复位,重新配置外设需要时间,反而可能错过一些实时性要求高的操作。所以WDRST只复位CPU核心和一些关键寄存器,外设配置尽量保留。
我列个对比表,大家一目了然:
| 复位源 | 触发条件 | 复位范围 | 启动时间 | 典型应用 |
|---|---|---|---|---|
| POR | 上电 | 全部寄存器 | 最长(约3-5ms) | 首次上电 |
| XRS | 外部引脚拉低 | 全部寄存器 | 中等(约1-2ms) | 手动复位、外部监控 |
| WDRST | 看门狗溢出 | 部分寄存器 | 最短(约0.5ms) | 程序跑飞恢复 |
3.3 复位时序:启动抖动的“元凶”
好,现在我们知道复位源了。但为什么复位会影响启动抖动?
原因在于:不同的复位源,启动时序不一样。POR启动时,内部振荡器需要稳定时间,PLL需要锁定时间,这些都需要等待。而WDRST启动时,很多时钟配置可能还保留着,启动路径更短。
我画了一张流程图,展示不同复位源下的启动路径差异:
从这张图可以看得很清楚:WDRST跳过了振荡器稳定和PLL锁定这两个耗时最长的阶段,所以启动时间比POR和XRS短得多。这个时间差,就是启动抖动的来源之一。
3.4 实战:如何消除复位引起的启动抖动
知道了问题在哪,解决方案就呼之欲出了。我总结了三条经验:
- 启动时检查复位标志:在main函数的第一行代码,读取复位状态寄存器,判断是哪种复位。如果是WDRST,可以跳过一些耗时的初始化步骤。
- 统一启动路径:如果你发现系统对启动时间有严格要求,可以考虑在WDRST后也执行完整的初始化流程,但用更快的时钟配置来缩短时间。
- 喂狗时机要合理:不要在中断里喂狗,也不要在初始化完成前喂狗。我习惯在进入主循环后,先完成所有关键初始化,再开启看门狗。
代码片段:检查复位标志
// 启动时检查复位源
void CheckResetSource(void)
{
uint16_t resetFlag = SysCtrlRegs.RESC.bit.POR;
if(resetFlag == 1)
{
// POR复位,需要完整初始化
FullInit();
}
else if(SysCtrlRegs.RESC.bit.XRS == 1)
{
// XRS复位,也需要完整初始化
FullInit();
}
else if(SysCtrlRegs.RESC.bit.WDRST == 1)
{
// WDRST复位,可以跳过部分初始化
QuickInit();
}
// 清除复位标志
SysCtrlRegs.RESC.all = 0xFFFF;
}