32. IWDT——独立看门狗定时器

32.1. IWDT简介

IWDT (Independent Watchdog Timer) 由一个14位的向下计数器组成,用于从应用程序中的意外错误中恢复。 应用程序必须在允许的计数窗口内进行刷新计时器,如果允许计数器下溢或者是在有效刷新周期外刷新的话, IWDT将复位MCU或生成不可屏蔽中断(NMI)。

32.1.1. IWDT特性

IWDT 特性:
  • 使用自带时钟源 (IWDTCLK)

  • 使用14位下行计数器进行计数

  • 可以设置安全属性 TrustZone

32.2. IWDT功能框图剖析

图

32.2.1. IWDT 时钟源

32.2.1.1. 计数器时钟

独立看门狗时钟来自 IWDTCLK , IWDTCLK 最大的时钟频率是 15000Hz ,可以使用 RA 配置编辑器的 BSP 设置 IWDTCLK 分频器。 从计数器第一次刷新到产生复位或NMI中断的最大时间要比35秒略少一点。

32.2.1.2. 独立看门狗超时时间计算

  1. 首先,独立看门狗的输入时钟频率为 15000hz

  2. 时钟分频比等于 256

  3. 将循环周期设为 2048 cycles

  4. 那么,可以得到独立看门狗的时钟频率 15000Hz / 256 = 58.59hz

  5. 周期时间等于 1/58.59hz = 17.067 ms

  6. 最终计算出设置的超时时间 = 17.067 ms x 2048 cycles = 34.95 秒

注解

cycles :配置的循环周期次数,此数值越大,超时时间越长。

32.2.2. IWDT 模块电路功能讲解

当 “功能选择寄存器0” 中的 “IWDT启动模式选择位(OFS0.IWDTSTRT)” 为 “自动启动模式” 时,才能使用 IWDT ,否则IWDT将被禁用。 在重置状态下,“功能选择寄存器0 (OFS0)” 中的各项设置如下:

复位状态解除后,计数器自动从IWDT超时时间选择位(OFS0.IWDTTOPS[1:0])中选择的值开始倒数。 在此之后,只要程序继续正常操作并且在刷新允许的时间内刷新计数器,每次刷新计数器并继续下计数时,计数器中的值都会重置。 只要这个过程继续,IWDT就不会输出复位信号。然而,如果由于程序崩溃或由于在刷新允许的时间外尝试刷新时发生了刷新错误而导致计数器不足, IWDT将断言重置信号或不可屏蔽中断请求/中断请求(IWDT_NMIUNDF)。

复位信号或不可屏蔽中断请求/中断请求产生后,计数器计数1个周期后重新加载超时时间, 在down计数器中设置超时时间的值,开始计数。复位输出或中断请求输出可以用IWDT复位中断请求选择位(OFS0.IWDTRSTIRQS)进行选择。 不可屏蔽中断请求或中断请求可以通过IWDT下流/刷新错误中断启用位进行选择(NMIER.IWDTEN)。

下图显示了在以下条件下的操作示例:

  • 自启动模式(OFS0.Iwdtstrt = 0)

  • 启用了不可屏蔽中断请求输出(OFS0.Iwdtrstirqs = 0)

  • 窗口结束位置为0% (OFS0.IWDTRPES[1:0] = 10b)

  • 窗口起始位置为100% (OFS0.IWDTRPSS[1:0] = 10b)

图

32.2.3. 独立看门狗(IWDT)与看门狗(WDT)功能对比

独立看门狗(IWDT)与看门狗(WDT)的不同点如下:

  1. 时钟源不一样,WDT使用外部时钟电路作为时钟源,而IWDT为了稳定性和安全性自带时钟源。

  2. WDT可以设置寄存器启动和自启动两种模式,然而在大多数 MCU上面, IWDT只能够设置成自启动这一种模式。

而独立看门狗(IWDT)与看门狗(WDT)也有很多相似点,主要如下:

  1. 都可以选择复位的范围(窗口值)。

  2. 都可以设置在睡眠模式下是否启动。

  3. 都可以设置NMI中断和复位重启。

关于相同的方面在上一章节已经介绍过了,这里不再赘述。

32.2.4. 怎么使用IWDT

独立看门狗一般用来检测和解决由程序引起的故障,比如一个程序正常运行的时间是50ms, 在运行完这个段程序之后紧接着进行喂狗,我们设置独立看门狗的定时溢出时间为60ms, 比我们需要监控的程序50ms多一点, 如果超过60ms还没有喂狗,那就说明我们监控的程序出故障了, 跑飞了,那么就会产生系统复位,让程序重新运行。

32.3. IWDT实验

32.3.1. 硬件设计

  1. IWDG一个

  2. 按键一个

  3. LED两个

IWDG属于单片机内部资源,不需要外部电路,需要一个外部的按键和LED,通过按键来喂狗,喂狗成功LED亮,喂狗失败,程序重启,LED灭一次。 我们使用LED灯和按键。

32.3.2. 软件设计

32.3.2.1. 新建工程

由于本实验需要按键和LED灯,因此我们可以在上一章节的实验例程基础上继续修改程序。

对于 e2 studio 开发环境:

拷贝一份我们之前的 e2s 工程 “30_WDT”, 然后将工程文件夹重命名为 “30_IWDT”,最后再将它导入到我们的 e2 studio 工作空间中。

对于 Keil 开发环境:

拷贝一份我们之前的 Keil 工程 “30_WDT”, 然后将工程文件夹重命名为 “30_IWDT”,并进入该文件夹里面双击 Keil 工程文件,打开该工程。

工程新建好之后,删除工程中“bsp_wdt.c” 和 “bsp_wdt.h”文件。的在工程根目录的 “src” 文件夹下面新建 iwdt 文件夹, 再进入 “iwdt” 文件夹里面新建源文件和头文件:“bsp_iwdt.c” 和 “bsp_iwdt.h”。 工程文件结构如下。

文件结构
30_IWDT
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ iwdt
   │  ├─ bsp_iwdt.c
   │  └─ bsp_iwdt.h
   └─ hal_entry.c

32.3.2.2. FSP配置

首先打开 “31_IWDT” 项目的 FSP 配置界面,接下来我们要在这个界面里配置芯片的引脚及其相应的功能。

双击 configuration.xml 打开配置界面: 然后点开依次点击 Stacks -> New Stack -> Search… 里输入 IWDT 选着 Independent Watchdog

图

并且在堆栈中配置独立看门狗的名称以及NMI回调函数。

图

然后我们点击 BSP 的属性settings界面,找到 OFS0 register settings -> WDT 去设置 WDT 的属性。

图

要注意,对于寄存器启动的看门狗实验我们只能在新建的堆栈选项中进行配置, 而对于自启动看门狗实验只能在BSP的堆栈中进行配置,在模块堆栈中进行配置是没有用的。 在本实验中为了防止看门狗超时时间过长,影响实验效率,故把看门狗的周期设定为16周期, 最大超时时间也就是2.1秒左右。

配置完成之后可以按下快捷键“Ctrl + S”保存, 最后点右上角的 “Generate Project Content” 按钮,让软件自动生成配置代码即可。

32.3.2.3. NMI 和 复位

NMI就是会执行一个中断服务函数,这个中断函数是不能够被打断的,拥有最高的中断优先级。 一般是用在一些重要的数据上面,如果直接复位,这些数据将不被保存,这个时候我们可以写一个服务程序去保存重要数据, 这也是看门狗最重要的功能。 可以在NMI中断程序中通过软件复位或跳转到程序开头进行程序的重新运行。

复位就是在不断电的情况下,把当前 MCU 及运行数据清零后的启动。在本实验中使用NMI,也就是不可屏蔽中断来进行试验。

32.3.2.4. WDT初始化函数

初始化函数
/*初始化看门狗并启动计数器*/
void IWDT_Init(void)
{
   //如果使用J-Link调试器进行调试的话需要加上这一句话
   R_DEBUG->DBGSTOPCR_b.DBGSTOP_WDT = 0;

   //初始化看门狗(WDT)模块
   R_IWDT_Open(&g_iwdt0_ctrl, &g_iwdt0_cfg);

}

32.3.2.5. 喂狗函数

喂狗函数
/*喂狗*/
void IWDT_Feed(void)
{
   /*喂狗,刷新递减计数器的值*/
   R_IWDT_Refresh(&g_iwdt0_ctrl);
}

32.3.2.6. NMI中断服务函数

NMI不可屏蔽中断函数
/* 当看门狗NMI发生时中断回调 */
void iwdt_callback (wdt_callback_args_t * p_args)
{
   /*防止编译器产生关于函数中没有使用形参的警告*/
   (void) p_args;

   /*蓝色LED亮,请注意,在这里LED灯函数为代指,
    *实际应用中,这里应该放最重要的函数,比如保存重要数据等*/
   LED1_OFF;
   LED2_ON;
   R_BSP_SoftwareDelay(3, BSP_DELAY_UNITS_SECONDS);

   /* 通过软件复位MCU*/
   __NVIC_SystemReset();
}

32.3.2.7. 主函数

主函数
/*按键中断回调函数*/
void key1_callback(external_irq_callback_args_t *p_args)
{
   (void) p_args;

   /*按键按下触发中断,进行喂狗操作*/
   IWDT_Feed();
}

void hal_entry(void)
{
   /*红色LED亮3秒*/
   LED1_ON;
   R_BSP_SoftwareDelay(3,BSP_DELAY_UNITS_SECONDS);

   /*按键中断初始化*/
   g_external_irq_on_icu.open(&key1_ctrl, &key1_cfg);
   g_external_irq_on_icu.enable(&key1_ctrl);

   /*初始化看门狗并开启计数器*/
   IWDT_Init();

   while(1)
   {
      /*红色LED灯灭,在这里只是代指,
       *实际上这部分应该写需要被WDT监控的程序*/
   }

#if BSP_TZ_SECURE_BUILD
   /* Enter non-secure code */
   R_BSP_NonSecureEnter();
#endif
}

注解

使用 J-Link 调试器时,WDT 计数器不计数,因此不会重置设备或生成 NMI。若要使监视器能够在调试时计数并生成重置或 NMI,请在应用程序中添加 R_DEBUG->DBGSTOPCR_b.DBGSTOP_IWDT = 0 代码。

32.3.2.8. 下载验证

将程序下载到开发板内,红色LED灯亮,随后看门狗启动, 需要在不超过2.1秒左右内的时间按下按键1(SW2)来刷新计数器的数值(喂狗)。 一旦超过这个时间,看门狗计数器下溢,将产生NMI,也就是不可屏蔽中断,届时红色LED灯灭,蓝色LED灯会亮三秒, 随后软件复位,程序从头运行。