ARM 看门狗定时器

一、什么是看门狗、有什么用

(1) 看门狗定时器和普通的定时器并无本质区别。定时器可以设定一个时间,在这个时间完成之前定时器不断计时,时间到的时候,定时器会复位 CPU(重启系统)。
(2 )系统正常工作的时候当然不希望被重启,但是系统受到干扰、极端环境等可能会产生异常工作或者不工作,这种状态可能会造成不良影响(至少是不工作),此时解决方案就是重启系统。
(3) 普通设备重启不是问题,但是有些设备人工重启存在困难。这时候我们希望系统能够自己检验自己是否已经跑飞,并且在意识到自己跑飞的时候,可以很快的(几个ms或者更短)自我重启。这个功能就要靠看门狗定时器来实现。
(4) 典型应用的情景是:我们在应用程序中打开看门狗设备,初始化好给它一个时间,然后应用程序使用一个线程来喂狗,这个线程的执行时间安全短于看门狗的复位时间。当系统(或者应用程序)异常后,喂狗线程自然就不工作了,然后到时候看门狗就会复位。
(5) 补充:实战中有时候为了绝对的可靠,我们并不会用 SoC 中自带的看门狗,而是使用专门的外置的看门狗芯片来实现看门狗。


二、S5PV210 看门狗定时器的结构框图

看门狗定时器使用的时钟域及其频率。
在这里插入图片描述


(1) PCLK_PSYS 经过两级分频后生成 WDT(watchdog timer)的时钟周期,然后把要定的时间写到 WTDAT 寄存器中,刷到 WTCNT 寄存器中去减 1,减到 0 时(定时时间到)产生复位信号或中断信号。
在这里插入图片描述


在这里插入图片描述

(2) 典型应用中是配置为产生复位信号,我们应该在 WTCNT 寄存器减到 0 之前给 WTDAT 寄存器中重新写值以喂狗。
(3) 注意,看门狗定时器的计数值无法自动装载。在第一次使能看门狗之前,需要手动装载看门狗定时器的计数值。
在这里插入图片描述


三、看门狗定时器的主要寄存器

1、WTCON

在这里插入图片描述


2、WTDAT

在这里插入图片描述


3、WTCNT

在这里插入图片描述


4、WTCLRINT

在这里插入图片描述


四、看门狗定时器的编程实践

1、产生中断信号

文件名:wdt.c

#include "stdio.h"
#include "init.h"

#define		WTCON		(0xE2700000)
#define		WTDAT		(0xE2700004)
#define		WTCNT		(0xE2700008)
#define 	WTCLRINT	(0xE270000C)

#define 	rWTCON		(*(volatile unsigned int *)WTCON)
#define 	rWTDAT		(*(volatile unsigned int *)WTDAT)
#define 	rWTCNT		(*(volatile unsigned int *)WTCNT)
#define 	rWTCLRINT	(*(volatile unsigned int *)WTCLRINT)


unsigned int pow(unsigned int base, unsigned int exponent)
{
    if (base == 2)
    {
        return (0x1 << exponent);
    }
    else
    {
	unsigned int sum = 1, temp = 0;
	for (temp = 0; temp < exponent; temp++)
	{
	    sum *= base;
	}

	return sum;
    }
}

/*************************************************************************/

#define         BIT_LOCATION_WTCON_PRESCALER_VALUE     (0xff << 8)
#define         BIT_WTCON_PRESCALER                    (pow(2,8))


#define         WTCON_FUNC_WDT_TIMER_ENABLE            (0x1  << 5)
#define         WTCON_FUNC_WDT_TIMER_DISABLE           (0x0  << 5)

#define         BIT_LOCATION_WTCON_CLOCK_SELECT        (0b11 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_16             (0b00 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_32             (0b01 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_64             (0b10 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_128            (0b11 << 3)

#define         WTCON_FUNC_INTERRUPT_GENERATION_ENABLE (0x1  << 2)
#define         WTCON_FUNC_INTERRUPT_GENERATION_DISABLE (0x0 << 2)

#define         BIT_LOCATION_WTCON_RESET               (0b1  << 0)
#define         WTCON_FUNC_RESET_ENABLE                (0x1  << 0)
#define         WTCON_FUNC_RESET_DISABLE               (0x0  << 0)


//初始化 WDT 使之可以产生中断
void wdt_init_interrupt(void)
{
    //第一步,设置好预分频器和分频器,得到时钟周期是 128 us
    rWTCON &= ~(BIT_LOCATION_WTCON_PRESCALER_VALUE);
    //t_watchdog = 1/( PCLK / (Prescaler value + 1) / Division_factor )
    rWTCON |= (65 * BIT_WTCON_PRESCALER); // 1MHZ

    rWTCON &= ~(BIT_LOCATION_WTCON_CLOCK_SELECT);
    rWTCON |= (WTCON_FUNC_CLOCK_SELECT_128);  // 1/128 MHZ, T = 128us

    //第二步,设置中断和复位信号的使能或禁止
    rWTCON |= (WTCON_FUNC_INTERRUPT_GENERATION_ENABLE); // enable wdt interrupt

    rWTCON &= ~(BIT_LOCATION_WTCON_RESET);  
    rWTCON |= (WTCON_FUNC_RESET_DISABLE);   //disable wdt reset

    //第三步,设置定时时间
    //WDT 定时计数个数,最终定时时间为这里的值 x 时钟周期
    rWTDAT = 10000;   //定时 1.28s
    rWTCNT = 10000;   //定时 1.28s

    //第四步,先把所有寄存器都设置好之后,再去打开看门狗
    rWTCON |= (WTCON_FUNC_WDT_TIMER_ENABLE);  //enable wdt
}

//wdt 的中断处理程序
void isr_wdt(void)
{
    static int i = 0;
    //看门狗定时器时间到了,应该做的有意义的事情
    printf("wdt interrupt, i = %d...\r\n", i++);

    //清除中断
    intc_clearVectaddr();
    rWTCLRINT = 1;
}

现象截图:可以看到,wdt 中断的时间确实是 1.28s左右发生一次。
在这里插入图片描述


2、产生复位信号

#include "stdio.h"
#include "init.h"

#define		WTCON		(0xE2700000)
#define		WTDAT		(0xE2700004)
#define		WTCNT		(0xE2700008)
#define 	WTCLRINT	(0xE270000C)

#define 	rWTCON		(*(volatile unsigned int *)WTCON)
#define 	rWTDAT		(*(volatile unsigned int *)WTDAT)
#define 	rWTCNT		(*(volatile unsigned int *)WTCNT)
#define 	rWTCLRINT	(*(volatile unsigned int *)WTCLRINT)


unsigned int pow(unsigned int base, unsigned int exponent)
{
    if (base == 2)
    {
        return (0x1 << exponent);
    }
    else
    {
	unsigned int sum = 1, temp = 0;
	for (temp = 0; temp < exponent; temp++)
	{
	    sum *= base;
	}

	return sum;
    }
}

/*************************************************************************/

#define         BIT_LOCATION_WTCON_PRESCALER_VALUE     (0xff << 8)
#define         BIT_WTCON_PRESCALER                    (pow(2,8))


#define         WTCON_FUNC_WDT_TIMER_ENABLE            (0x1  << 5)
#define         WTCON_FUNC_WDT_TIMER_DISABLE           (0x0  << 5)

#define         BIT_LOCATION_WTCON_CLOCK_SELECT        (0b11 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_16             (0b00 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_32             (0b01 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_64             (0b10 << 3)
#define         WTCON_FUNC_CLOCK_SELECT_128            (0b11 << 3)

#define         BIT_LOCATION_WTCON_INTERRUPT           (0b1  << 2)
#define         WTCON_FUNC_INTERRUPT_GENERATION_ENABLE (0x1  << 2)
#define         WTCON_FUNC_INTERRUPT_GENERATION_DISABLE (0x0 << 2)

#define         BIT_LOCATION_WTCON_RESET               (0b1  << 0)
#define         WTCON_FUNC_RESET_ENABLE                (0x1  << 0)
#define         WTCON_FUNC_RESET_DISABLE               (0x0  << 0)


//初始化 WDT 使之可以产生中断
void wdt_init_interrupt(void)
{
    //第一步,设置好预分频器和分频器,得到时钟周期是 128 us
    rWTCON &= ~(BIT_LOCATION_WTCON_PRESCALER_VALUE);
    //t_watchdog = 1/( PCLK / (Prescaler value + 1) / Division_factor )
    rWTCON |= (65 * BIT_WTCON_PRESCALER); // 1MHZ

    rWTCON &= ~(BIT_LOCATION_WTCON_CLOCK_SELECT);
    rWTCON |= (WTCON_FUNC_CLOCK_SELECT_128);  // 1/128 MHZ, T = 128us

    //第二步,设置中断和复位信号的使能或禁止
    rWTCON &= ~(BIT_LOCATION_WTCON_INTERRUPT); 
    rWTCON |= (WTCON_FUNC_INTERRUPT_GENERATION_DISABLE); // disable wdt interrupt

    rWTCON &= ~(BIT_LOCATION_WTCON_RESET);  
    rWTCON |= (WTCON_FUNC_RESET_ENABLE);   //enable wdt reset

    //第三步,设置定时时间
    //WDT 定时计数个数,最终定时时间为这里的值 x 时钟周期
    rWTDAT = 10000;   //定时 1.28s
    rWTCNT = 10000;   //定时 1.28s

    //第四步,先把所有寄存器都设置好之后,再去打开看门狗
    rWTCON |= (WTCON_FUNC_WDT_TIMER_ENABLE);  //enable wdt
}

//wdt 的中断处理程序
void isr_wdt(void)
{
    static int i = 0;
    //看门狗定时器时间到了,应该做的有意义的事情
    printf("wdt interrupt, i = %d...\r\n", i++);

    //清除中断
    intc_clearVectaddr();
    rWTCLRINT = 1;
}

现象截图:可以看到,定时1s之后,芯片就复位了,不会再打印信息。
在这里插入图片描述


源自朱友鹏老师.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值