5.18 IWDG 使用说明
本章说明 N32H49x 标准外设库中 IWDG 驱动的文件组成与 7 个公开函数,以及 IWDG_Reset 示例。IWDG 由 LSI 驱动、独立于主程序运行,在死循环或 MCU 卡死时以系统复位恢复;键值、预分频与重装载寄存器的访问保护和配置流程请配合用户手册的“独立看门狗(IWDG)”章节阅读。
5.18.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32h49x_std_periph_driver/inc/n32h49x_iwdg.h |
定义键值、写访问配置、预分频与状态标志枚举,声明 7 个公开函数 |
firmware/n32h49x_std_periph_driver/src/n32h49x_iwdg.c |
实现上述 7 个函数:写访问密钥序列、写入预分频与重载值、重载与启动计数器、运行时冻结与状态读取 |
projects/n32h49x_EVAL/examples/IWDG/ |
IWDG 示例根目录,含 IWDG_Reset 1 个示例 |
projects/n32h49x_EVAL/examples/IWDG/IWDG_Reset/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
projects/n32h49x_EVAL/bsp/ |
该示例引用的公共板级文件:串口日志与毫秒延时函数 |
5.18.2 API 参考
以下 7 个公开函数按 n32h49x_iwdg.h 的声明顺序分为 3 组;每个条目给出功能摘要与 n32h49x_iwdg.c 中该函数正上方的注释原文。
配置与重载
IWDG_WriteConfig、IWDG_SetPrescalerDiv、IWDG_CntReload、IWDG_ReloadKey
使能与冻结
IWDG_Enable、IWDG_Freeze_Enable
状态
IWDG_GetStatus
void IWDG_WriteConfig(IWDOG_WRITE_CONFIG IWDG_WriteAccess)使能或禁止对 IWDG_PREDIV 与 IWDG_RELV 寄存器的写保护。
name IWDG_WriteConfig.
fun Enables or disables write protection to IWDG_PREDIV and IWDG_RELV registers.
param IWDG_WriteAccess
- IWDG_WRITE_ENABLE
- IWDG_WRITE_DISABLE
return none
使用提示: 实现把参数值直接写入 IWDG->KEY;IWDG_WRITE_ENABLE 取值为 0x5555,用于打开 IWDG_PREDIV、IWDG_RELV 的写访问,IWDG_WRITE_DISABLE 取值为 0x0000。
void IWDG_SetPrescalerDiv(uint8_t IWDG_Prescaler)IWDG_Prescaler 指定 IWDG 的预分频值。
name IWDG_SetPrescalerDiv.
fun IWDG_Prescaler specifies the IWDG prescaler value.
param IWDG_Prescaler :
- IWDG_PRESCALER_DIV4
- IWDG_PRESCALER_DIV8
- IWDG_PRESCALER_DIV16
- IWDG_PRESCALER_DIV32
- IWDG_PRESCALER_DIV64
- IWDG_PRESCALER_DIV128
- IWDG_PRESCALER_DIV256
return none
void IWDG_CntReload(uint16_t Reload)设置 IWDG 重载值。
name IWDG_CntReload.
fun Sets IWDG reload value.
param Reload :
-0x000 ~ 0xFFF
return none
void IWDG_ReloadKey(void)用 IWDG_RELV 寄存器中定义的值重新加载 IWDG 计数器。
name IWDG_ReloadKey.
fun Reload IWDG counter with value defined in IWDG_RELV register.
param none
return none
void IWDG_Enable(void)启动看门狗计数器。
name IWDG_Enable.
fun Start watch dog counter.
param none
return none
void IWDG_Freeze_Enable(FunctionalState Cmd)在运行模式下 IWDG 运行时冻结或解冻 IWDG。
name IWDG_Freeze_Enable.
fun Freeze or unfreeze IWDG while IWDG is running in run mode.
param Cmd :
- ENABLE
- DISABLE
return none
使用提示: 实现按 Cmd 写入 IWDG->KEY:ENABLE 写 0x4567 冻结计数器,其余值写 0x89AB 解冻。
FlagStatus IWDG_GetStatus(IWDG_STATUS_FLAG IWDG_FLAG)检查指定的 IWDG 标志是否置位。
name IWDG_GetStatus.
fun Checks whether the specified IWDG flag is set or not.
param IWDG_FLAG :
- IWDG_PVU_FLAG
- IWDG_CRVU_FLAG
- IWDG_FRZF_FLAG
return FlagStatus :
- RESET
- SET
5.18.3 Demo 示例说明
本节说明 IWDG 的 1 个示例:IWDG_Reset 配置 IWDG 超时并在主循环中定期喂狗,用于演示喂狗超时触发的系统复位。
5.18.3.1 IWDG_Reset IWDG 复位
工程目录: projects/n32h49x_EVAL/examples/IWDG/IWDG_Reset/
初始化串口日志与指示灯→检查上次复位是否由 IWDG 触发并点亮 LED1→打开写访问、配置预分频与重载值→启动 IWDG 计数器→主循环翻转 LED3、延时后重载计数器
| 项目 | 源码解读 |
|---|---|
| 功能 | 配置 IWDG 计数器时钟为 LSI/32、超时约 250 ms,主循环每 249 ms 重载一次计数器; 正常运行时 LED3 持续闪烁,喂狗超时会触发 IWDG 复位,复位后点亮 LED1 并在串口打印 reset by IWDG。 |
| 源码组成 | src/main.c:main 与 LedInit、LedOn、LedOff、LedBlink,以及 LSI_TIM_MEASURE 下的 GTIM1_ConfigForLSI;inc/main.h:包含 n32h49x_iwdg.h、n32h49x_usart.h、misc.h、log.h;src/n32h49x_it.c、inc/n32h49x_it.h:中断服务函数(含 GTIM1_IRQHandler);readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:IWDG 由 LSI 驱动,预分频 IWDG_PRESCALER_DIV32;重载值: IWDG_CntReload(LsiFreq / 128),LsiFreq 取 32000 Hz,超时约 250 ms;写访问: IWDG_WriteConfig(IWDG_WRITE_ENABLE) 打开 IWDG_PREDIV、IWDG_RELV 写访问;指示灯:LED1 为 PA3、LED3 为 PA8,推挽输出。 |
| 程序与数据路径 | main 调用 log_init,初始化并熄灭 LED1、LED3;检查 RCC_FLAG_IWDGRSTF:置位时点亮 LED1、打印 reset by IWDG 并清除复位标志,否则熄灭 LED1;随后 IWDG_WriteConfig、IWDG_SetPrescalerDiv、IWDG_CntReload、IWDG_ReloadKey、IWDG_Enable 依次配置并启动 IWDG;while(1) 中翻转 PA8(LED3)、延时 249 ms,再用 IWDG_ReloadKey 重载计数器。 |
| 主要 API | IWDG_WriteConfig、IWDG_SetPrescalerDiv、IWDG_CntReload、IWDG_ReloadKey、IWDG_Enable |
| 验证方法 | 编译下载并复位运行后 LED3 约每 249 ms 翻转、持续闪烁,说明喂狗正常; 把 systick_delay_ms 的参数改为 251 及以上使喂狗超时,系统将持续复位、LED1 点亮,串口打印 reset by IWDG。 |
| 使用提示 | 硬件开发环境为全功能板 N32H497ZGL7_EVB V1.0; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1; 未定义 LSI_TIM_MEASURE 时超时值直接取 LsiFreq / 128,不测量实际 LSI 频率,实际超时会随 LSI 频率离散略有偏差。 |
核心代码解读与移植
示例先检测本次复位是否来自 IWDG,再依次完成写访问、预分频、重载与启动,最后在主循环中定期喂狗。
数据路径: RCC_FLAG_IWDGRSTF 复位标志 → IWDG_WriteConfig、IWDG_SetPrescalerDiv、IWDG_CntReload、IWDG_Enable 写入 IWDG_PREDIV、IWDG_RELV 与 IWDG_KEY → 主循环 IWDG_ReloadKey 重载计数器 → LED3 翻转、复位时 LED1 点亮
1. 初始化并点亮指示灯。 main 先调用 log_init,把 LED1(PA3)与 LED3(PA8)初始化为推挽输出并熄灭。
log_init();
log_info("--- IWDG demo reset ---\n");
LedInit(LED1_GPIO_PORT, LED1_GPIO_PIN);
LedInit(LED3_GPIO_PORT, LED3_GPIO_PIN);
LedOff(LED1_GPIO_PORT, LED1_GPIO_PIN);
LedOff(LED3_GPIO_PORT, LED3_GPIO_PIN);
移植到其它板卡时改 LED1_GPIO_PORT、LED1_GPIO_PIN、LED3_GPIO_PORT、LED3_GPIO_PIN 这组宏即可,LED 初始化与 IWDG 本身无关。
2. 检查复位来源并显示。 先使能 PWR 时钟,再读取 RCC_FLAG_IWDGRSTF:若本次复位由 IWDG 触发就点亮 LED1、打印提示并清除复位标志,否则熄灭 LED1。
/* Check if the system has resumed from IWDG reset */
if(RCC_GetFlagStatus(RCC_FLAG_IWDGRSTF) != RESET)
{
/* IWDGRST flag set */
/* Turn on LED1 */
LedOn(LED1_GPIO_PORT, LED1_GPIO_PIN);
log_info("reset by IWDG\n");
/* Clear reset flags */
RCC_ClearResetFlag();
}
else
{
/* IWDGRST flag is not set */
/* Turn off LED1 */
LedOff(LED1_GPIO_PORT, LED1_GPIO_PIN);
}
移植时要保留清除复位标志的调用,否则下一次上电仍会读到旧的复位来源;读取该标志前需使能 PWR 时钟。
3. 配置并启动 IWDG。 main 先打开写访问,再写入预分频与重载值,然后重载并启动计数器。
/* IWDG timeout equal to 250 ms (the timeout may varies due to LSI frequency
dispersion) */
/* Enable write access to IWDG_PR and IWDG_RLR registers */
IWDG_WriteConfig(IWDG_WRITE_ENABLE);
/* IWDG counter clock: LSI/32 */
IWDG_SetPrescalerDiv(IWDG_PRESCALER_DIV32);
/* Set counter reload value to obtain 250ms IWDG TimeOut.
Counter Reload Value = 250ms/IWDG counter clock period
= 250ms / (LSI/128)
= 0.25s / (LsiFreq/32)
= LsiFreq/(32 * 4)
= LsiFreq/128 */
log_debug("LsiFreq is: %d\n", LsiFreq);
IWDG_CntReload(LsiFreq / 128);
/* Reload IWDG counter */
IWDG_ReloadKey();
/* Enable IWDG (the LSI oscillator will be enabled by hardware) */
IWDG_Enable();
LsiFreq 默认为 32000 Hz,配合预分频 IWDG_PRESCALER_DIV32 得到约 250 ms 超时;改超时时间要同时核对预分频因子与 IWDG_CntReload 的参数。
4. 主循环定期喂狗。 循环里翻转 LED3、延时 249 ms,再调用 IWDG_ReloadKey 重载计数器。
while(1)
{
/* Toggle LED3 */
LedBlink(LED3_GPIO_PORT, LED3_GPIO_PIN);
/* Insert 249 ms delay */
systick_delay_ms(249);
/* Reload IWDG counter */
IWDG_ReloadKey();
}
喂狗间隔须小于超时时间(这里 249 ms 小于 250 ms);把延时改到超时以上会触发 IWDG 复位。
对应源码: src/main.c
5.18.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| 修改预分频与重装载值 | 这两个寄存器带写保护,需先向 IWDG_KEY.KEYV[15:0] 写入 0x5555 打开写访问;写入其他值会重新启用写保护,重载操作(写 0xAAAA)也会使寄存器再次变为写保护。 |
用户手册 |
| 更新标志未清零 | 修改预分频前须确认 IWDG_STS.PVU 为 0、修改重载值前须确认 IWDG_STS.CRVU 为 0;更新期间读取 IWDG_PREDIV.PD[2:0] 或 IWDG_RELV.REL[11:0] 无效。 |
用户手册 |
| 启用方式 | 向 IWDG_KEY.KEYV[15:0] 写入 0xCCCC 启动计数器;通过选项字节使能硬件看门狗后,上电即自动运行。 |
用户手册 |
| 复位使能位 | PWR_CTRL2.IWDGRSTEN 为 1 时计数器到 0 产生系统复位;该位为 0 时 IWDG 会计数但不产生复位。 |
用户手册 |
| 调试模式 | 内核停止时 IWDG 计数器是否停止由调试模块的 DBG_CTRL.IWDG_STOP 位决定:该位为 1 时计数器停止,为 0 时继续计数。 |
用户手册 |
| 停止计数 | 一旦 IWDG 使能,除非发生系统复位或向 IWDG_KEY.KEYV[15:0] 写入 0x4567 配置运行时冻结,IWDG 不会停止计数。 |
用户手册 |