RK 看门狗 WatchDog

 

看门狗 又叫 watchdog timer 是为了能够防止程序跑飞而使用的一种机制
若系统正常 喂狗的程序会正常的进行 一旦系统出现死机、异常等现象 喂狗会停止 系统在一定的时间内没有收到喂狗 就自动重启 恢复到正常状态
其实就是一个定时器电路 一般有一个输入,叫喂狗,一个输出到MCU的RST端,MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给 WDT 清零,
如果超过规定时间不喂狗(一般在程序跑飞时),WDT 定时超过,就会给出一个复位信号到MCU,使MCU复位. 防止MCU死机.

 Platform: RK3288
OS: Android 5.1.1
Kernel: 3.10.0

1.1.设备树 看门狗配置 

dtsi片段并不能说明全部-设备树语法是分层的,因此属性(尤其是status)可能仍会被包含基本SoC的板级.dts覆盖. dtsi文件 

kernel\arch\arm\boot\dts\rk3288-tb_zk_r322_V3.dts

1
2
3
4
5
&watchdog {
    status = "okay";
    //rockchip,irq = <0>;
    rockchip,atboot = <0>;
};

kernel\arch\arm\boot\dts\rk3288.dtsi

1
2
3
4
5
6
7
8
9
10
11
12
watchdog: wdt@2004c000 {
    compatible = "rockchip,watch dog";
    reg = <0xff800000 0x100>;
    clocks = <&pclk_pd_alive>;
    clock-names = "pclk_wdt";
    interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
    rockchip,irq = <1>;
    rockchip,timeout = <60>;
    rockchip,atboot = <1>;
    rockchip,debug = <0>;
    status = "disabled";
};

1.2.kernel\drivers\watchdog\rk29_wdt.c  

a.rk29_wdt_set_heartbeat  定时器设定一个中断的时间间隔maxtime  22s

wdt_clock = devm_clk_get(&pdev->dev, "pclk_wdt");

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* timeout unit second */
int rk29_wdt_set_heartbeat(int timeout)
{
    unsigned int count = 0;
    unsigned int torr = 0, acc = 1, maxtime = 0;   
    unsigned int freq = clk_get_rate(wdt_clock);
 
    if (timeout < 1)
        return -EINVAL;
    //0x80000000 is the max count of watch dog
    maxtime = 0x80000000 / freq + 1;
    if(timeout > maxtime)
        timeout = maxtime;
         
    count = timeout * freq;
    count /= 0x10000;
 
    while(acc < count){
        acc *= 2;
        torr++;
    }
    if(torr > 15){
        torr = 15;
    }
    DBG("%s:torr:%d, count:%d, maxtime:%d s\n", __func__, torr, count, maxtime);
    wdt_writel(torr, RK29_WDT_TORR);
    return 0;
}

b.rk29_wdt_keepalive 喂狗

1
2
3
4
5
6
/* functions */
void rk29_wdt_keepalive(void)
{
    if (wdt_base)
        wdt_writel(0x76, RK29_WDT_CRR);
}

c. rk29_wdt_probe   中断申请函数request_irq详解

rk29_wdt_proberk29_wdt_probe 中断申请  系统回调函数 

1
2
3
4
5
6
7
8
9
10
ret = request_irq(wdt_irq->start, rk29_wdt_irq_handler, 0, pdev->name, pdev);
 
/* interrupt handler code */
 
static irqreturn_t rk29_wdt_irq_handler(int irqno, void *param)
{
    DBG("RK29_wdt:watchdog timer expired (irq)\n");
    rk29_wdt_keepalive();
    return IRQ_HANDLED;
}

 d.rk29_wdt_ioctl

WDIOC_KEEPALIVE :喂狗
WDIOC_SETTIMEOUT :设置超时值
WDIOC_GETTIMEOUT :获取超时值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static long rk29_wdt_ioctl(struct file *file,   unsigned int cmd,
                            unsigned long arg)
{
    void __user *argp = (void __user *)arg;
    int __user *p = argp;
    int new_margin;
    DBG("%s\n", __func__);
    switch (cmd) {
    case WDIOC_GETSUPPORT:
        return copy_to_user(argp, &rk29_wdt_ident,
            sizeof(rk29_wdt_ident)) ? -EFAULT : 0;
    case WDIOC_GETSTATUS:
    case WDIOC_GETBOOTSTATUS:
        return put_user(0, p);
    case WDIOC_KEEPALIVE:
        DBG("%s:rk29_wdt_keepalive\n", __func__);
        rk29_wdt_keepalive();
        return 0;
    case WDIOC_SETTIMEOUT:
        if (get_user(new_margin, p))
            return -EFAULT;
        if (rk29_wdt_set_heartbeat(new_margin))
            return -EINVAL;
        rk29_wdt_keepalive();
        return put_user(tmr_margin, p);
    case WDIOC_GETTIMEOUT:
        return put_user(tmr_margin, p);
    default:
        return -ENOTTY;
    }
}

1.3.JNI  ioctl系统调用来控制设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#define    XH_WATCHDOG                          "/dev/watchdog"
#define      WDIOC_APP_WDT_CTL                      100
 
 
static void watchdog_close(JNIEnv *env, jobject obj, jint fd)
{
        write(fd, "V", 1);
         
        ioctl(fd, WDIOC_APP_WDT_CTL, NULL);
         
        close(fd);
}
static void watchdog_feed(JNIEnv *env, jobject obj, jint fd)
{
        write(fd, "a", 1);
}
static jint watchdog_open(JNIEnv *env, jobject obj)
{
        int fd=0;
        int timeout=0;
         
        timeout=40;
         
        fd=open(XH_WATCHDOG, O_RDWR,0);
         
        if(fd>0)
        {
            ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
            ioctl(fd, WDIOC_APP_WDT_CTL, &timeout);
        }
         
      return fd;
}

  

 

posted @   CrushGirl  阅读(2233)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示