
1. 问题现象与根因分析1.1 量产里的“玄学”复位固件一样板子不一样先讲一个我实际碰到的场景产品用 STM32F103C8T6几百套板子烧同一个固件结果装配线上零零散散有不到 5% 的板子在启动后 1~3 秒内反复复位要么是卡死在某个外设初始化流程里要么是跑起来没多久就“咔”一下重启。用示波器抓 NRST 引脚能看到明显的低电平复位脉冲而且复位间隔极不稳定。一开始怀疑是电源或者晶振问题换过芯片、换过样板问题依旧。最后把目光放到 IWDGIndependent Watchdog独立看门狗上才找到真正的根因不是固件逻辑不一致而是 IWDG 初始化本身存在“隐藏不一致”。开发阶段用的是开发板芯片是代理商挑过的LSILow Speed Internal低速内部 RC 振荡器频率正好接近数据手册的典型值所以看门狗超时时间符合预期。但量产批次里芯片来自不同晶圆LSI 的离散性被充分释放有的芯片 LSI 只有 30kHz有的却飙到 55kHz 以上。而我们的 IWDG 重装载值是按典型值 40kHz 算的结果就是看门狗实际超时时间从设计的 1.6 秒变成了 1.1 秒到 2.9 秒不等。对于主循环周期本来就接近超时阈值的固件来说LSI 偏高的芯片在极端负载下就会频繁被咬复位。这个案例说明一个问题很多人把 IWDG 初始化当成“固定写死”的事情觉得只要代码一样行为就应该一样。但在 STM32 上IWDG 的计时基准是 LSI而 LSI 的本质是一个没有外部校准的片上 RC 振荡器它的频率随工艺、温度、电压变化离散范围比你想象中大得多。同型号芯片也不能幸免这正是标题里强调“同型号”的原因。1.2 根因一LSI 频率不是一个固定值STM32 的 IWDG 完全独立于主时钟域使用 LSI 作为时钟源。LSI 的好处是便宜、内部集成、无需外部器件坏处是精度差。以 STM32F1 系列为例数据手册上 LSI 典型值是 40kHz但全温度范围下可能是 30kHz~60kHz这已经是最宽的情况。到了 STM32F4 系列LSI 典型值变成 32kHz范围也经常是 17kHz~47kHz。不同系列、不同封装、不同批次实测值可能千差万别。IWDG 的超时时间计算公式是Tout (4 × 2^PRER × RLR) / LSI_freq其中 PRER 是预分频寄存器值0~7对应分频系数 4、8、16、32、64、128、256RLR 是 12 位重装载值0~4095。如果按典型 LSI 频率算好 RLR但实际 LSI 偏差了 ±30%那超时时间也会跟着偏差 ±30%甚至更大。这里有个容易被忽略的点同型号芯片的数据手册会给你一个典型值但不会保证每颗芯片都落在典型值上。手册一般只会给出一个很宽的“最小/最大”范围。如果固件里把 LSI 当成精确 40kHz 来用那你实际上就是在赌芯片的工艺一致性。对于要求不高的消费类产品这可能没问题但如果固件主循环时间窗口很紧或者产品需要在高温/低温环境下运行这个赌注就太危险了。1.3 根因二选项字节里的硬件看门狗开关除了 LSI 离散性还有一个容易被忽略的差异来源Flash 选项字节中的硬件看门狗开关IWDG_SW。STM32 的 IWDG 支持两种启动方式软件启动和硬件启动。软件启动是指上电复位后 IWDG 默认关闭需要代码写键寄存器 0xCCCC 启动硬件启动则是通过选项字节配置让芯片一上电 IWDG 就自动运行不需要软件参与。这个选项字节在出厂时可能已经被预设成“硬件看门狗模式”也可能是“软件模式”。如果你买到的芯片渠道不同、批次不同或者二手芯片的选项字节被前一个用户改过那么你的代码可能在两种模式下行为完全不一样。举个实际例子某批芯片被配置成硬件看门狗模式那么芯片上电到代码执行 IWDG 初始化之前看门狗已经开始倒计时了。如果你的初始化代码在启动早期被中断、耗时过长或者在某些条件下跳过了 IWDG 初始化分支看门狗就会在系统还没启动完的时候咬复位。而在其他批次的芯片上代码正常工作。这个现象经常被误判成“芯片质量有问题”实际上是你没有显式地、幂等地处理 IWDG 的初始化状态。处理方式很简单在初始化 IWDG 之前先读取选项字节确认当前的 IWDG_SW 状态并在代码里对“看门狗已经被硬件启动”的情况做兼容不要假设复位后 IWDG 一定是关闭的。1.4 根因三复位后 LSI 启动时序最后一个细节是 LSI 的稳定时间。LSI 从复位释放后开始振荡但它不是瞬间稳定的。不同芯片、不同温度下LSI 达到稳定频率需要几十微秒到几百微秒不等。如果你在 main 函数的一开头甚至是在 SystemInit 里就立刻启动 IWDG此时 LSI 可能还在“爬升”阶段。更糟的是如果你在 LSI 不稳定的时候写入了重装载值并启动看门狗那么第一次超时时间可能会远小于预期导致芯片立即复位。规范做法是先启动 LSI等待 LSI 就绪标志如果系列支持或者用一条足够长的延时例如延时 1ms确保 LSI 稳定然后再配置 IWDG 寄存器。很多标准库的 RCC 代码里其实已经帮你开了 LSI但没有等它稳定就直接返回这个坑我踩过。2. IWDG 初始化机制与差异点全解2.1 三个关键寄存器一个都不能写错IWDG 的核心寄存器只有三个键寄存器KR、预分频寄存器PR和重装载寄存器RLR另外还有一个状态寄存器SR用于指示更新状态。KR 是 16 位只写寄存器写入不同的键值执行不同操作0x5555解除 PR 和 RLR 的写保护0xAAAA把 RLR 的值加载到递减计数器也就是喂狗0xCCCC启动看门狗PR 控制分频系数复位值为 0对应 4 分频。RLR 是 12 位重装载值决定看门狗超时周期复位值为 0xFFF也就是 4095。标准初始化流程是/* 解除写保护 */ IWDG-KR 0x5555; /* 设置预分频值例如 4 对应 64 分频 */ IWDG-PR 4; /* 设置重装载值 */ IWDG-RLR reload; /* 等待寄存器更新完成 */ while (IWDG-SR); /* 重新加载计数器并启动看门狗 */ IWDG-KR 0xAAAA; IWDG-KR 0xCCCC;注意PR 和 RLR 必须在写完 0x5555 之后立即写入并且它们是有写保护的。有些开发者在喂狗的时候又写了一次 0x5555这不会导致错误但会影响代码可读性。真正的坑是如果你先写了 0xCCCC 启动看门狗再想修改 PR 或 RLR仍然可以写入但这些修改不会立即生效要等下一次喂狗时才会加载到计数器。这种“修改延迟生效”的机制很容易让人误判以为改了重装值就能立即改变超时时间。2.2 标准初始化流程看起来一样实际结果不一样我见过很多项目里的 IWDG 初始化代码都是这样的固定模式void IWDG_Config(void) { IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_64); IWDG_SetReload(1250); IWDG_ReloadCounter(); IWDG_Enable(); }这段代码在开发板上一跑喂狗周期 2.1 秒左右看起来没问题。但到了量产如果芯片的 LSI 是 48kHz那么实际超时时间就变成 1.75 秒如果 LSI 是 32kHz就变成 2.62 秒。如果固件的主循环在最坏情况下需要 1.9 秒才能喂一次狗那么在 LSI 偏高的芯片上就会间歇性复位。关键在于IWDG 初始化代码本身没有错错的是它隐含了一个假设LSI40kHz。要解决这个问题你有两条路一是根据 LSI 的实际频率动态计算 RLR二是在设计阶段就把 LSI 的离散性纳入超时余量计算。前者是精准方案适合对超时时间有严格要求的场景后者是粗粒度方案实现简单适合看门狗只用来兜底、不在乎精确时间的场景。我在第 3 节会分别讲。2.3 LSI 到底有多不准这里我用一个表格直观展示几个常见系列的 LSI 参数大家设计时一定以具体型号最新数据手册为准系列LSI 典型值常见手册范围影响STM32F140kHz30kHz~60kHzIWDG 超时偏差最大可达 ±50%STM32F432kHz17kHz~47kHz低温或高温下偏差更明显STM32L037kHz30kHz~50kHz低功耗模式下 LSI 还会受到电源影响STM32G032kHz28kHz~36kHz部分系列内置校准范围相对窄不要觉得这些范围是理论值我实测过一批 F103常温下 LSI 从 36kHz 到 52kHz 的都有。即使同一片 PCB 上的两颗芯片在 25℃ 环境下也可能差 15%。到了 -20℃ 和 70℃ 的环境频率漂移更明显。LSI 校准逻辑并不复杂用已知频率的高精度时钟去测量 LSI 产生的信号周期反推 LSI 频率再用这个频率去计算 IWDG 重装载值。STM32 的 RTC 如果使用 LSI 作为时钟源其实天然就是一个“LSI 分频计数器”我们可以利用 RTC 的秒中断来测量 LSI 的实际频率思路我放到第 4 节讲。2.4 为什么说“同型号”之间也会不一致很多应用的 IWDG 超时时间设计裕量很大比如目标 5 秒超时即使 LSI 偏差 ±50%实际超时也在 3.3~7.5 秒之间系统照样能跑。但有些应用不一样比如电机控制、传感器采集、通信协议栈主循环周期本身就有波动喂狗周期贴着超时上限这时候 LSI 偏差就变成了致命问题。还有一类场景是“低功耗唤醒后喂狗”这在电池类产品中很常见。设备进入 Stop 模式后LSI 可能被关闭或保持运行唤醒后的 LSI 重新稳定时间更长。如果你的 IWDG 在 Stop 模式下仍然运行某些系列 IWDG 在 Stop 模式下继续工作那么唤醒后必须在几百微秒内完成喂狗。这时如果 LSI 频率偏低看门狗实际超时时间比预期短唤醒程序还没跑完就被复位。这个现象在开发机上很难复现因为开发板芯片的 LSI 偏高掩盖了问题。所以“同型号”只是一个相对概念。只要 LSI 是 RC 振荡器它就存在片间差异只要你的初始化基于典型值就存在一致性风险。下面要讲的一致性配置核心思想就是消除对典型值的依赖。3. 一致性配置方案从“能用”到“精准”3.1 方案一按最坏情况折算 RLR零成本兜底如果不做校准最稳的做法是在初始化时用 LSI 的最大频率和最小频率分别验算超时范围确保在极端情况下仍满足“最小喂狗周期”或“最大允许死机时间”。假设你希望看门狗最短也要保证 2 秒才复位意思是即便 LSI 偏高也不能小于 2 秒。这时应该用 LSI 的最大可能频率来计算 RLR因为 LSI 越高超时越短。公式如下RLR (Tout_min × LSI_max) / (4 × 2^PRER)反过来如果你希望看门狗最长不要超过 5 秒避免死机后长时间不复位应该用 LSI 最小可能频率来计算RLR (Tout_max × LSI_min) / (4 × 2^PRER)以 F103 为例取 LSI_max60kHzPRER464 分频目标最小超时 2 秒RLR (2 × 60000) / 64 1875这个值在 12 位范围内没问题。当 LSI 实际为 30kHz 时实际超时时间为Tout (1875 × 64) / 30000 4.0 秒也就是说最坏情况下看门狗复位时间从 2 秒变成了 4 秒仍然在可接受范围内。这种方案不需要额外代码只需要在初始化参数里把手册的边界值算进去适合快速修复量产问题。但这种方案的代价是超时范围很宽你要保证固件在所有 LSI 范围内都能在最短超时前喂狗。如果主循环最坏响应时间接近 2 秒那这个方案就不够用了需要更精准的校准。3.2 方案二利用 RTC 秒中断校准 LSI精准方案的核心是测出 LSI 的实际频率然后动态计算重装载值。常见做法是让 RTC 使用 LSI 作为时钟源并配置成 1 秒中断同时开启一个由系统主时钟HSE 或 HSI驱动的通用定时器用于测量两次 RTC 秒中断之间的精确时间间隔。原理是这样RTC 的 1 秒中断本质上是把 LSI 频率经过一组分频器后得到的“秒脉冲”这个秒脉冲的实际周期等于 LSI 计数了多少个时钟周期。如果 LSI 频率偏高RTC 秒脉冲就会比真实 1 秒短如果 LSI 频率偏低RTC 秒脉冲就会比真实 1 秒长。用高精度的定时器测量这个秒脉冲的实际长度就能反推 LSI 频率。具体推算过程如下假设 RTC 配置的异步预分频为 127同步预分频为 312那么 LSI 需要经过 128 × 313 40064 个周期才产生一次秒中断。在实际系统中RTC 中断间隔内通用定时器计数了 delta_us 个微秒。那么 LSI 实际频率为LSI_actual 40064 × 1000000 / delta_us例如实测 delta_us 1,250,000即真实间隔 1.25 秒则 LSI_actual 40064 × 1000000 / 1250000 32.05kHz。这个结果直接用于 IWDG 重装载值计算精度可以做到 1% 以内。3.3 方案三校准值固化运行时快速初始化如果你的产品对启动速度有要求不想每次上电都花几百毫秒等待校准完成可以在产线阶段做一次性校准把测得的 LSI 频率写入片内 Flash 的某个保留扇区或者写入外部 EEPROM。固件启动时直接读取校准值再计算 RLR初始化时间可以控制在几十微秒内。这种做法适合温度变化不剧烈的产品。如果产品工作温度范围很宽最好还是每次上电都校准因为 LSI 频率随温度变化可以达到 10%~20%。但也可以做折中启动时读取上次校准值和当前温度如果温度变化超过阈值就重新校准否则使用存储值。我个人的建议是对于不是特别苛刻的应用每次上电校准是最稳妥的。反正系统启动时本来就要做很多外设初始化多花几十毫秒校准 LSI 完全可以接受。3.4 各方案对比与选型建议方案精度实现成本适用场景按最坏情况折算低超时范围宽极低只改参数看门狗仅做兜底主循环响应快RTC 秒中断校准高偏差可控制在 1%中等需要 RTC 和 TIM对喂狗窗口有严格要求校准值固化高但受温度影响中高需要产线支持启动时间敏感、产线可校准多级看门狗中高需要额外硬件安全等级高的工业产品从工程实践看我最推荐方案二每次上电用 RTC 秒中断做校准不依赖产线不增加硬件代码量也不大。如果产品的喂狗周期裕量很大方案一就够了没必要折腾。4. 校准流程实操以 STM32F103 HAL 为例4.1 准备工作与系统时钟确认这里以 STM32F103C8T6 为例系统时钟使用外部 8MHz 晶振倍频到 72MHzAPB1 分频为 2所以 PCLK136MHz定时器时钟为 72MHz因为 TIM 时钟会再倍频一次。如果你用的是别的型号或别的时钟配置一定要先查清楚 TIM 的实际时钟频率否则下面计算全废。校准前的硬件准备只有一样一个能输出高电平脉冲的 GPIO用于在喂狗周期内翻转方便用示波器验证。没有示波器也可以用调试器观察内部定时器计数值。4.2 移植校准代码校准代码分为四步初始化 TIM2 用于微秒计数、初始化 RTC 并产生秒中断、在秒中断里计算 delta_us、根据 delta_us 计算 LSI 频率。TIM2 初始化如下使用 HAL 库void TIM2_Init_For_LSI_Calib(void) { __HAL_RCC_TIM2_CLK_ENABLE(); TIM2_Handle.Instance TIM2; TIM2_Handle.Init.Prescaler 72 - 1; /* 72MHz / 72 1MHz即 1us 计数 */ TIM2_Handle.Init.CounterMode TIM_COUNTERMODE_UP; TIM2_Handle.Init.Period 0xFFFFFFFF; /* 32 位计数器溢出时间很长 */ TIM2_Handle.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(TIM2_Handle); HAL_TIM_Base_Start(TIM2_Handle); }RTC 初始化时选择 LSI 作为时钟源并确保 LSI 已经启动void RTC_Init_For_LSI_Calib(void) { __HAL_RCC_RTC_ENABLE(); __HAL_RCC_LSI_ENABLE(); /* 等待 LSI 就绪 */ while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) RESET) { } RTC_Handle.Instance RTC; RTC_Handle.Init.HourFormat RTC_HOURFORMAT_24HOUR; RTC_Handle.Init.AsynchPrediv 127; /* 异步分频 128 */ RTC_Handle.Init.SynchPrediv 312; /* 同步分频 313 */ HAL_RTC_Init(RTC_Handle); /* 使能秒中断注意需要在 HAL_RTC_Init 之后 */ HAL_RTCEx_SetSecond_IT(RTC_Handle); }然后在 RTC 秒中断回调函数里记录 TIM2 当前计数extern volatile uint32_t g_lsi_last_tick; extern volatile uint32_t g_lsi_delta_us; extern volatile uint8_t g_lsi_calib_done; void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc) { static uint32_t last_tick 0; uint32_t now_tick __HAL_TIM_GET_COUNTER(TIM2_Handle); if (last_tick ! 0) { g_lsi_delta_us now_tick - last_tick; g_lsi_calib_done 1; } last_tick now_tick; }这里用 32 位 TIM2 计数器1MHz 计数频率下需要 4294 秒才会溢出完全不用担心溢出问题。如果使用 16 位定时器就需要注意溢出计数建议直接选用 32 位定时器TIM2/TIM5。4.3 计算实际 LSI 频率与 IWDG 重装载值当 g_lsi_calib_done 置 1 后就可以计算 LSI 实际频率#define RTC_OVERFLOW_COUNT (128 * 313) /* 40064 */ uint32_t LSI_GetActualFrequency(void) { uint32_t delta_us g_lsi_delta_us; if (delta_us 0) { return 0; } /* 40064 个 LSI 周期对应 delta_us 微秒反推 LSI 频率 */ return (uint32_t)((uint64_t)RTC_OVERFLOW_COUNT * 1000000UL / delta_us); }得到 lsi_hz 后假设目标超时时间为 target_timeout_sec浮点选用 PRER464 分频计算 RLRuint32_t IWDG_CalculateReload(float target_timeout_sec, uint32_t lsi_hz) { uint32_t reload; /* Tout (4 * 2^PRER * RLR) / lsi_hzPRER4 时分频系数为 64 */ /* 所以 RLR Tout * lsi_hz / 64这里要求浮点或做整形化处理 */ reload (uint32_t)((target_timeout_sec * lsi_hz) / 64.0f); if (reload 4095) { reload 4095; } if (reload 0) { reload 1; } return reload; }然后按照标准流程写入 IWDG 寄存器void IWDG_InitWithCalibratedReload(uint32_t reload) { IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_64); IWDG_SetReload(reload); IWDG_ReloadCounter(); IWDG_Enable(); }注意HAL 库里也有对应的 LL 接口LL_IWDG_EnableWriteAccess(IWDG); LL_IWDG_SetPrescaler(IWDG, LL_IWDG_PRESCALER_64); LL_IWDG_SetReloadCounter(IWDG, reload); LL_IWDG_ReloadCounter(IWDG); LL_IWDG_Enable(IWDG);如果你用的是 LL 库代码会更简洁。4.4 验证用示波器或 GPIO 翻转确认超时时间校准完成后为了验证实际超时时间是否符合预期可以在主循环里加一个测试专用 GPIO每次喂狗前翻转一次然后故意停止喂狗用示波器观察引脚持续时间。这样能直接测出真实超时时间。正常情况是设计的 target_timeout_sec 比如 2.0 秒实测在 1.98~2.02 秒之间说明校准有效。如果没有示波器也可以把实际计算出的 reload 值和 lsi_hz 通过串口打印出来看不同芯片之间的差异。我实测中不同芯片的 lsi_hz 可能会在 35kHz 到 48kHz 之间变动但最终的喂狗超时时间基本都能控制在目标值的 1% 以内。4.5 校准过程中的典型注意事项第一RTC 本身可能已经被业务代码占用。如果你的系统已经用 RTC 做日历或者闹钟那需要复用现有的 RTC 中断不要同时初始化两个 RTC否则冲突。可以只在开机启动阶段临时用 RTC 做校准校准完成后重新配置 RTC 为业务模式。第二LSI 校准过程中最好关闭其他高优先级中断否则 RTC 秒中断回调里的 TIM2 计数器读取可能被延迟导致 delta_us 偏大。如果系统允许可以在进入校准前挂起无关中断校准完再恢复。第三不要在校准过程中使用调试器打断。进入调试模式后内核暂停但 LSI 和 RTC 仍然在跑TIM2 的计数也在跑这会导致 delta_us 测量结果完全错误。我之前就因为这个原因看到校准出来的 LSI 频率一会 20kHz 一会 80kHz折腾了半天才发现是调试器暂停导致的。第四IWDG 一旦启动就不可停止。如果你在校验过程中不小心把 IWDG 启动了后面想继续调试就会很痛苦。建议在校准阶段先不启动 IWDG只打印计算结果确认 reload 值合理后再真正启用 IWDG。5. 常见问题与排查实录5.1 表IWDG 相关异常速查现象可能原因排查方向上电立即复位硬件看门狗选项字节被启用初始化之前超时先看选项字节 IWDG_SW再检查启动代码耗时喂狗间隔正常但随机复位LSI 偏高导致实际超时小于预期实测 LSI重新计算 RLR校准后喂狗仍不稳定RTC 秒中断回调延迟校准期间关闭其他高优先级中断调试器连接后复位IWDG 在调试暂停时继续运行设置 DBGMCU 里 IWDG 冻结或用调试器选项暂停 IWDG低温下复位频率变高LSI 随温度升高/降低漂移按最坏温度范围计算 RLR或冷启动校准复位后 RTC 时间不准RTC 秒中断实际周期偏离 1s用 LSI 校准值修正 RTC 分频参数5.2 校准后仍然复位问题出在哪最常见的是校准代码本身使用了 IWDG 或 RTC 中断但你在校准过程中又开了其他外设导致秒中断的响应时间不固定。比如串口 DMA 中断、外部按键中断频繁触发RTC 中断回调被无限延迟delta_us 被拉大反推出来的 LSI 频率偏低最后算出的 RLR 也偏低实际超时反而更短。解决办法是校准阶段设置一个“校准窗口”在这个窗口内关闭无关中断只在 RTC 秒中断里做最少操作。同时给 delta_us 设置一个合理范围比如正常 LSI 应该落在 20kHz~60kHz折算成 delta_us 应该在 660000~2000000 之间。如果超出这个范围直接把这次校准结果丢弃下次再测。5.3 硬件看门狗模式下的“失控”初始化不少工程师不知道 STM32 还有硬件看门狗模式。如果芯片选项字节里 IWDG_SW0看门狗从上电就开始运行默认预分频 4默认重装载 4095这意味着超时时间为 (4 × 4095) / LSI。若 LSI 为 40kHz大约是 0.4095 秒。如果固件在启动后 400ms 内没有喂狗芯片就会复位。这个问题在量产中特别容易漏掉。因为很多开发板或者刚拿到的芯片选项字节默认是软件模式你从来没遇到过硬件模式下的情况。一旦遇到复位时间非常早往往被误判为“芯片坏了”或者“晶振没起振”。排查方法很简单用 ST-Link Utility 或者 STM32CubeProgrammer 读取选项字节看 IWDG_SW 到底是 1 还是 0。如果是 0并且你希望使用软件模式直接烧录时将选项字节修改为 1或者代码里显式初始化看门狗确保在任何模式下都能正常工作。5.4 调试时一暂停就复位别再把锅甩给代码还有一个特别常见的坑调试器一暂停IWDG 照样跑然后芯片就复位了。这其实不是代码问题而是调试环境没有配置 IWDG 冻结。在 Cortex-M3/M4 上可以通过 DBGMCU 寄存器控制外设是否在调试暂停时停止时钟。HAL 库中可以用以下代码开启__HAL_DBGMCU_FREEZE_IWDG();这个选项最好放在初始化早期。开启后当你用调试器设置断点暂停时IWDG 时钟会被冻结避免调试过程中看门狗复位。注意这个配置只影响调试状态正常运行不受影响。5.5 用 ST-Link Utility 和烧录器观察到的差异很多工程师习惯用 ST-Link Utility 或 STM32CubeProgrammer 烧录固件后顺手读一下 Flash 内容发现两次读出的内容不一样就怀疑芯片有问题。其实这往往和 LSI 无关而是选项字节区被修改过。但如果你利用这些工具读取 RCC 相关的寄存器有时能看到 LSIRDY 位长时间不为 1说明 LSI 起振偏慢。这个现象在某些批次芯片上更明显也可以作为判断 LSI 健康度的参考。我的建议是量产阶段把读保护、选项字节、IWDG_SW 的设置一并固化成烧录脚本不要依赖每颗芯片的出厂默认值。只有把初始状态统一了IWDG 初始化行为才可能一致。6. 一点个人经验总结我在这个项目上踩过的最大坑就是过于相信“典型值”三个字。数据手册给的 40kHz、32kHz只是理论参考不是标称精度。LSI 本质上就是一个 RC 振荡器它的使命是“提供一个不需要外部晶振的慢速时钟”而不是“提供一个精确时钟”。你要拿它来跑 RTC、跑看门狗就必须接受它的离散性并且用校准去补偿。后来我在多个项目里沿用了这套“RTC 秒中断 定时器计数”的校准方案不限于 IWDG还包括低功耗模式的 RTC 唤醒计时、片内 RTC 日历的时间精度修正。每次上电做一次 LSI 校准整个系统的时钟精度都有明显提升。关键是代码量不大不依赖额外硬件也不要求产线配合非常适合嵌入式工程师自己落地。如果大家在项目里也遇到过“同型号芯片、不同表现”的问题建议先别急着怀疑芯片质量问题先查三个地方LSI 实际频率是多少、选项字节里的硬件看门狗是不是启用状态、调试时有没有冻结 IWDG。把这三个点确认清楚80% 的看门狗玄学问题都能找到明确答案。