• 第26章_瑞萨MCU零基础入门系列教程之独立看门狗定时器-IWDT


    本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id=728461040949

    配套资料获取:https://renesas-docs.100ask.net

    瑞萨MCU零基础入门系列教程汇总https://blog.csdn.net/qq_35181236/article/details/132779862


    第26章 独立看门狗定时器-IWDT

    本章目标

    • 了解A6M5处理器的看门狗定时器及其工作原理;
    • 学会使用RASC配置看门狗定时器,使用其接口函数;

    26.1 RA6M5的WDT外设

    26.1.1 WDT的特性

    IWDT (Independent Watchdog Timer)由一个14位的向下计数器组成,可以将应用程序从错误中恢复处理(比如重启系统)。应用程序必须在允许的计数窗口内进行刷新计时器,如果计数器下溢了,IWDT将复位MCU或生成不可屏蔽中断(NMI)。

    瑞萨RA6M5处理器的看门狗定时器的特性见下表:

    独立看门狗的时钟源是一个独立的时钟IWDTCLK,PCLKB最大的时钟频率是15kHz,可以使用RASC在BSP中设置IWDTCLK的分频系数。

    26.1.2 IWDT的系统框图

    IWDT的系统框图如下图所示:

    26.1.3 IWDT和WDT的异同

    1. 差异点

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

    • 时钟源不一样,WDT使用外部时钟电路作为时钟源,而IWDT自带时钟源;
    • WDT有寄存器启动和自启动两种模式,IWDT只有自启动这一种模式;
    1. 相同点

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

    • 都可以选择复位的范围(窗口值);
    • 都可以设置在睡眠模式下是否启动;
    • 都可以设置NMI中断和复位重启;

    26.1.4 IWDT的工作原理

    1. 超时时间计算

    以IWDTCLK=15kHz为例,假设对IWDT进行了以下配置:

    • 分频系数位256
    • 超时时间周期为2048cycles

    那么IWDT的超时时间为:

    image3

    1. 运行状态分析

    在“Option Function Select Register 0”寄存器中,对于IWDT有一个模式选择位[OFS0.IWDTSTRT]:它被写为0时,IWDT的自动启动模式被使能;写为1就是关闭IWDT的计数。

    只有在复位状态下,以下对IWDT在OFS0中的设置才会有效:

    • 配置OFS0.IWDTCKS[3:0]来配置IWDT的时钟分频系数;
    • 配置OFS0.IWDTRPSS[1:0]和OFS0.IWDTRPES[1:0]来设置IWDT的窗口监测始末位置;
    • 配置OFS0.IWDTTOPS[1:0]来设置IWDT的超时周期值cycles;
    • 配置OFS0.IWDTRSTIRQS来使能IWDT的重置输出和中断请求;

    当复位状态结束后,IWDT的计数器将会立刻向下计数。在RA6M5的用户手册中展示了一个IWDT的窗口刷新例图:

    总结下来就是:

    • 在窗口期内刷新看门狗会让IWDT计数器重新计数且不会触发任何事件或中断;
    • 在没有到窗口期起始位置刷新会触发刷新错误事件,并触发NMI中断;
    • 在超过窗口结束位置但是计数没有溢出期间刷新,会触发刷新错误事件,并触发NMI中断;
    • 如果IWDT计数溢出了,会触发技术溢出事件,触发NMI中断;

    也就是说,如果使用了窗口监测,只有在窗口期刷新定时器才会让系统正常运行,否则都会触发NMI中断。

    26.2 IWDT模块的使用

    26.2.1 模块配置

    1. 添加IWDT Stack

    在FSP的Stacks中添加IWDT模块的步骤如下图所示:

    1. 在BSP中配置IWDT

    从前文对IWDT的工作原理分析中可以看到,对于IWDT的所有操作都是在OFS0寄存器中进行配置的,而OFS0是在BSP板块里面的“RA6F5 Family”中,如下图所示:

    • Start Mode Select:IWDT启动模式选择

    1.1 IWDT is automatically activated after a reset (Autostart mode)(自启动)
    1.2 IWDT is Disabled

    • Timeout Period:IWDT计数周期值

    1.1 128 cycles
    1.2 512 cycles
    1.3 1024 cycles
    1.4 2048 cycles

    • Dedicated Clock Frequency Divisor:IWDT时钟分频系数(1/16/32/64/128/256),默认128;
    • Window End Position:窗口监测结束位置,默认0%,没有结束位置
    • Window Start Position:窗口监测开始位置,默认100%,没有开始位置
    • Reset Interrupt Request:选择使能触发复位的中断请求(NMI或Reset)
    • Stop Control:停止对WDT控制的条件

    1.1 Stop counting when in Sleep, Snooze mode, or Software Standby
    1.2 Counting continues (Note: Device will not enter Deep Standby Mode when selected. Device will enter Software Standby Mode)

    如果用户选择使用了NMI中断,还需要去RASC的Stacks中找到IWDG Stack模块,设置NMI的中断回调函数名,如下图所示:

    26.2.2 配置信息解读

    在RASC中配置IWDT并生成工程后,会在hal_data.c中生成结构体全局常量g_iwdt,它被用来表示IWDT设备,代码如下:

    const wdt_instance_t g_wdt =
    {
        .p_ctrl        = &g_iwdt_ctrl,
        .p_cfg         = &g_iwdt_cfg,
        .p_api         = &g_wdt_on_iwdt
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • p_ctrl:iwdt_instance_ctrl_t类型指针成员,用来记录设备状态,记录一些重要信息(比如回调函数);
    • p_cfg:指向IWDT的配置结构体,这个结构体的数值来自在RASC中对IWDT的配置,代码如下:
    const wdt_cfg_t g_iwdt_cfg =
    {
        .timeout = 0,
        .clock_division = 0,
        .window_start = 0,
        .window_end = 0,
        .reset_control = 0,
        .stop_control = 0,
        .p_callback = nmi_callback,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • p_api:指向了一个wdt_api_t结构体,这个结构体在r_iwdt.c中实现,它封装了IWDT设备的接口函数,代码如下:
    const wdt_api_t g_wdt_on_iwdt =
    {
        .open        = R_IWDT_Open,
        .refresh     = R_IWDT_Refresh,
        .statusGet   = R_IWDT_StatusGet,
        .statusClear = R_IWDT_StatusClear,
        .counterGet  = R_IWDT_CounterGet,
        .timeoutGet  = R_IWDT_TimeoutGet,
        .callbackSet = R_IWDT_CallbackSet,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    26.2.3 中断回调函数

    在RASC中配置了IWDT的中断回调函数名字,会在hal_data.h中声明此回调函数:

    #ifndef nmi_callback
    void nmi_callback(wdt_callback_args_t * p_args);
    #endif
    
    • 1
    • 2
    • 3

    用户需要实现这个回调函数,例如:

    void nmi_callback(wdt_callback_args_t * p_args)
    {
        (void)p_args;
    }
    
    • 1
    • 2
    • 3
    • 4

    26.2.4 API接口及其用法

    前文已经说过,在FSP库函数中是使用wdt_api_t结构体来封装IWDT的操作方法,原型如下:

    typedef struct st_wdt_api
    {
        fsp_err_t (* open)(wdt_ctrl_t * const p_ctrl, wdt_cfg_t const * const p_cfg);
        fsp_err_t (* refresh)(wdt_ctrl_t * const p_ctrl);
        fsp_err_t (* statusGet)(wdt_ctrl_t * const p_ctrl, wdt_status_t * const p_status);
        fsp_err_t (* statusClear)(wdt_ctrl_t * const p_ctrl, const wdt_status_t status);
        fsp_err_t (* counterGet)(wdt_ctrl_t * const p_ctrl, uint32_t * const p_count);
        fsp_err_t (* timeoutGet)(wdt_ctrl_t * const p_ctrl, 
                                 wdt_timeout_values_t * const p_timeout);
        fsp_err_t (* callbackSet)(wdt_ctrl_t * const p_api_ctrl, 
                                  void (* p_callback)(wdt_callback_args_t *),
                                  void const * const p_context, 
                                  wdt_callback_args_t * const p_callback_memory);
    } wdt_api_t;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    瑞萨在r_iwdt.c中实现一个wdt_api_t结构体,IWDT和WDT共用一套操作接口,读者请参考《25.2.4 API接口及其用法》了解这些函数的用法。

    26.3 独立看门狗定时器实验

    26.3.1 设计目的

    让用户学会使用瑞萨RA6M5的IWDT,并观察是否刷新看门狗的现象。

    26.3.2 硬件连接

    本实验会用到板载串口和按键,请读者参考前文配置。

    26.3.3 驱动程序

    1. 初始化IWDT

    调用open函数即可初始化IWDT,并启动它,代码如下:

    void IWDTDrvInit(void)
    {
        fsp_err_t err = g_iwdt.p_api->open(g_iwdt.p_ctrl, g_iwdt.p_cfg);
        assert(FSP_SUCCESS == err);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 刷新IWDT

    刷新IWDT比较简单,直接调用其refresh函数即可:

    void IWDTDrvRefresh(void)
    {
        fsp_err_t err = g_iwdt.p_api->refresh(g_iwdt.p_ctrl);
        assert(FSP_SUCCESS == err);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. NMI中断回调函数

    在RASC中使能了IWDT的NMI中断,需要自己实现NMI回调函数,代码如下:

    __WEAK void DataSaveProcess(void)
    {
    }
    void nmi_callback(wdt_callback_args_t * p_args)
    {
        (void)p_args;
        printf("\r\nWarning!Do your most important save working!!\r\n");
        DataSaveProcess();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 按键刷新定时器

    在按键消抖处理后,刷新看门狗定时器,代码如下:

    void KeyProcessEvents(void)
    {
        struct IODev *ptLedDev = IOGetDecvice("UserLed");
        struct IODev *ptKeyDev = IOGetDecvice("UserKey");
        ptLedDev->Write(ptLedDev, ptKeyDev->Read(ptKeyDev));
        IWDTDrvRefresh();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    26.3.4 测试程序

    在本次实验中,初始化了各个外设后,主循环中不用做任何事情,所有的操作都是在中断中完成的:

    • 按键中断
    • 滴答定时器消除按键抖动
    • NMI中断处理用户的紧急事件

    测试函数代码如下:

    void IWDTAppTest(void)
    {
        SystickInit();
        UARTDrvInit();
        
        struct IODev *ptdev = IOGetDecvice("UserKey");
        if(NULL != ptdev)
            ptdev->Init(ptdev);
        ptdev = IOGetDecvice("UserLed");
        if(NULL != ptdev)
            ptdev->Init(ptdev);
        
        IWDTDrvInit();
        
        while(1)
        {
            /* The code that is watched by iwdt */
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    26.3.5 测试结果

    将编译出来的二进制可执行文件烧录到板子上并运行,如果不按按键的话会得到例如下图这样的打印信息:

    image8


    本章完
  • 相关阅读:
    Sqilte3初步教程
    PMP考试敏捷占比有多少?解疑
    调试-Debug
    SpringBoot保姆级教程(二)SpringBoot入门
    Spring基础之AOP
    大咖云集,智慧碰撞|第 18 届 CLK 大会完整议程揭晓(内附报名通道)
    新生任务-1
    C++ STL进阶与补充(list容器)
    vue3学习源码笔记(小白入门系列)------ 组件更新流程
    高校节能环保建设
  • 原文地址:https://blog.csdn.net/qq_35181236/article/details/132866566