当前位置: 首页 > news >正文

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之后,芯片就复位了,不会再打印信息。
在这里插入图片描述


源自朱友鹏老师.

相关文章:

  • 重装wordpress/seo具体优化流程
  • 徐州网站网站建设/什么是软文推广
  • 青岛做一个网站多少钱/关键词排名推广
  • 北京想象力网站建设/百度升级最新版本
  • 学做奶油的网站/福州seo
  • 做一个网站的全部流程/seo服务包括哪些
  • Linux:git工具
  • 折半查找算法[二分查找法]算法的实现和解决整数溢出问题~
  • InfluxDB的查询优化
  • 1-货物摆放
  • 2023.1.16 (一) 上午 关于人口老龄化的研究——老龄化的式子表示及建国以来的老龄化情况
  • 5. 统计学基础2:协方差、相关系数、协方差矩阵
  • 【C++】二叉树进阶OJ题
  • 人工智能入门基础概念—教你正确打开人工智能世界的大门
  • 【自学Python】Python查找字符串
  • mybatis-plus分布式id重复问题
  • 译文 | Kubernetes 1.26:PodDisruptionBudget 守护不健康 Pod 时所用的驱逐策略
  • 数据库概述