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

&watchdog {
    status = "okay";
    //rockchip,irq = <0>;
    rockchip,atboot = <0>;
};

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

	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");

/* 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 喂狗

/* 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 中斷申請  系統回調函數 

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 :獲取超時值

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系統調用來控制設備

#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;
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM