uboot详解——cpu内部,外部和软件看门狗

uboot启动时,当将cpu运行模式设置为管理模式后,就要关闭看门狗了,那么看门狗是干什么的呢?

狗狗是我们的好朋友,有时候,一条好狗狗能够救主人的性命,”看门狗“是cpu的“好朋友”,它也能够在cpu出状况的时候把它救活。

看门狗其实就是一个可以在一定时间内被复位的计数器,当看门狗启动后,计数器开始自动计数,经过一定时间,cpu就会将这个计数器复位,如果没有被复位,计数器溢出就会对CPU产生一个复位信号使系统重启,这个复位的操作就是“喂狗”。

看门狗就这样兢兢业业的守着它的主人cpu,当cpu出状况的时候,就不能喂狗了,看门狗饿了就知道cpu不正常工作了,然后发送复位信号让cpu重新醒过来。

对于一些安装在户外的设备,可以很直接的体现它的价值,比如运营商在荒郊野岭安装了好多基站,如果这里的基站停止工作了,就需要派人去这个基站手动重启了,有了看门狗以后,只要过一段时间没有喂狗,看门狗就将系统重启,节省了不少人力。

看门狗主要分三种:

1、内置在cpu内部的看门狗

此类看门狗一般是将一个芯片中的定时器来作为看门狗,通过程序的初始化,写入初值,并启动定时器。程序按时对定时器赋初值(或复位),以免它饿了。这种看门狗是可以被禁用的(只要停止这个定时器即可),好比对那只要咬你的狗来个“葵花点穴手”。大部分CPU都内置看门狗,硬件原理可参考各芯片数据手册。
优点:可以通过程序改变初始时间,也可以随时禁用
缺点:需要初始化,如果程序在初始化、启动完成前跑飞或在禁用后跑飞,看门狗就无法复位系统,这样看门狗的作用就没有了,系统恢复能力降低。


2、独立的看门狗芯片

这种看门狗主要有一个用于喂狗的引脚(一般与CPU的GPIO相连)和一个复位引脚(与系统的RESET引脚相连),如果没有在一定时间内改变喂狗脚的电平,复位引脚就会改变状态复位CPU。此类看门狗一上电就开始工作,无法禁用。现在常用的芯片有:CAT705/CAT706、IMP706等等,溢出时间在1.6秒左右。 硬件原理可以参考各芯片数据手册和《基于Linux的嵌入式系统全程喂狗策略》。

优点:无须配置,上电即用。无法禁用,系统必须按时喂狗,系统恢复能力高。
缺点:无法灵活配置溢出时间,无法禁用,灵活性降低。

3、软件看门狗

这其实就是一个监控软件,对于硬件上出的问题它还是无能为力的,它主要对一些重要的软件进行监控。

一些重要的程序,必须让它一直跑着;而且还要时时关心它的状态——不能让它出现死锁现象。(当然,如果一个主程序会出现死锁,肯定是设计或者编程上的失误。首要做的事是Debug。)但如果时间紧迫可以用软件看门狗,暂时应急。

 这种监控软件运行不出现界面窗口,具有一定的隐蔽性;它定时判断目标进程是否运行在当前系统中,如果没有则启动目标进程;判断目标进程是否“无响应”,如果是则终止目标进程;如果目标进程“无响应”的次数超过一定的数量,则重启整个系统。它的目的也是复位,但是它主要市复位进程,实在不行才复位CPU。


第二种和第三种看门狗,在这里不作讨论,下面将讨论怎么使用内置在cpu内部的看门狗。

因为是内置在cpu内部,所以从电路图中就找不到看门狗的连接方式了,下面是看门狗的工作原理图:

从图中可以看出一下几点:

1. 看门狗使用的输入时钟是PCLK,关于时钟的知识将在后面进行详细分析

2. 看门狗的配置涉及到三个寄存器:控制寄存器(WTCON),数据寄存器(WTDAT),计数寄存器(WTCNT)

3.看门狗先将PCLK时钟进行预分频 (prescaler),分频的精度为0~255 (2的8次方-1 ,由WTCON的8-15位进行设置),预分频后再除以一个分频因子(division factor,由WTCON的4:3两位进行设置,一共有4中选择——16,32,64,128),有PCLK、prescaler和division factor三个变量以后,就可以计算出看门狗计数器递减时间间隔:

t_watchdog:看门狗计数器递减时间间隔,单位秒

PCLK:APB总线工作始终,单位HZ

prescaler value + 1:预分频大小,因为从0开始,所以需要加一

division_factor:分频因子,有4个档——16,32,64,128

当开发板一上电的时候,系统时钟是还没有初始化的,所以PCKL的时钟大小是和外部时钟一样的,cpu连接的外部晶振如下图:

所以刚上电时,PCKL的大小12MHz,WTCON[15:8]设置为74,除数因子选择16,通过上面公式可以计算出,看门狗控制器递减时间间隔0.1毫秒。将WTCNT里的值设置为0x2710(十进制10000),那么看门狗会每过一秒钟产生一次超时。


我们来看看控制寄存器(WTCON),数据寄存器(WTDAT),计数寄存器(WTCNT)芯片手册:


从上图可以看到WTCON的默认状态:

[0]=1 当看门狗计时器超时的时候,开启发送reset信号的功能

[2]=0 超时的时候不发送中断

[4:3]=00 默认分频因子是1/16, division_factor=16

[5]=1 开启看门狗计数器,看门狗会按照WTCNT中的初始值进行递减,直到超时

[15:8]=0x80 换成十进制是128, prescaler=128

因为刚开机的时候,PCLK=12M, prescaler=128, division_factor=16 , 所以可以计算出 t_watchdog=1/(12M/129/16)=(129*16)/(12000000)=0.000172s=0.172ms


上图是WTDAT寄存器的芯片手册,默认值是0x800, 十进制是2048

上图是计数器寄存器的芯片手册,默认值也是0x800,十进制是2048

所以刚上电的时候,看门狗的超时时间是:time_out=2048*0.000172=0.352252s 

0.352252s是如此的短暂,所以在开机的时候如果没有关闭看门狗,它将每隔0.352252s就发送一次reset信号重启cpu,不管uboot运行到哪个阶段,都将被看门狗终止并重启。

从上面可以得出结论,板子重启时,必须尽早关闭看门狗,以便后面的代码顺利执行

看门狗关闭以后,需要在什么时候开启呢?我们将会在后面分析uboot和内核代码的时候进行分析。


下面将使用一个例子演示对看门狗的操作。


Makefile

[plain]  view plain  copy
  1. watch_dog.bin:watch_dog.S    
  2.     arm-linux-gcc -g -c -o watch_dog.o watch_dog.S    
  3.     arm-linux-ld -Ttext 0x000 -g watch_dog.o -o watch_dog_elf    
  4.     arm-linux-objcopy -O binary -S watch_dog_elf watch_dog.bin    
  5.     
  6. clean:    
  7.     rm -rf watch_dog.bin *.o watch_dog_elf   

watch_dog.S

[plain]  view plain  copy
  1. @ 关闭看门狗实验  
  2. .text  
  3. .global _start  
  4. _start:  
  5.   ldr r0, = 0x53000000                       @ WTCON寄存器地址加载到r0  
  6.   
  7.   mov r1, #0                                 @ r1 = 0  
  8.   
  9.   str r1, [r0]                               @ 将r1里的值存到r0里地址里  

通过分析前面的寄存器的设置位可知,只要设置WTCON[5]为0即可,上述代码里,直接将整个WTCON寄存器里的位设置为0。


[plain]  view plain  copy
  1. @开启看门狗实验:  
  2. @watch_dog.S  
  3.   
  4.  .text  
  5.  .global _start  
  6.  _start:  
  7.         @ 设置看门狗控制寄存器  
  8.   
  9.   
  10.          ldr r0, =0x53000000                           @ 加载WTCON寄存器地址  
  11.   
  12.          @ 0x4a21 = [15:8]=74, [5]=1, [0]=1  
  13.   
  14.          ldr r1, =0x4a21                               @ 将0x4a21保存到r1里  
  15.   
  16.          str r1, [r0]                                  @ 将r1里的值存入r0指向的地址  
  17.   
  18.          @ 设置看门狗计数寄存器,该寄存器的值在上电后被加载, 1秒超时  
  19.   
  20.          ldr r2, =0x53000008                           @ 加载WTCNT寄存器地址  
  21.   
  22.          ldr r3, =0x2710                               @ 将0x2710保存到r1里  
  23.   
  24.          str r3, [r2]                                  @ 将r3里的值存入r2指向的地址  
  25.   
  26.   
  27.          bl led_on                                     @ 调用led_on代码  
  28.   
  29.    
  30.   
  31. loop:  
  32.   
  33.          b loop                                        @ 死循环  
  34.   
  35. led_on:  
  36.         ldr r0,=0x56000010    
  37.     mov r1,#0x15400    
  38.     str r1,[r0]    
  39.               
  40.     ldr r0,=0x56000014    
  41.     mov r1,#0x100    
  42.     str r1,[r0]    
  43.     mov pc,lr    

程序开始定义两个常量地址,分别是WTCON,WTCNT的地址,ENRTY后面是程序的正文部分,首先通过ldr指令加载WTCON的地址到r0里,将0x4a21这个数加载到r1里,0x4a21是我们通过设置WTCON [15:8]=74 [7:6]=0,[5]=1,[4:1]=0, [0]=1得到的16进制数,将其值存入到r0地址里,这样WTCON里就是我们设置各位的值,然后同样道理再将0x2710存到WTCNT数据寄存器里,设置数据寄存器的值为0x2710。

为了看到看门狗的重启效果,我们加入了一个小程序,用来点亮led灯,将上述代码在linux下编译完后,烧写到NORFLASH里可以看到每过1秒钟,开发板的led灯就闪一下。


知识扩展

开启了看门狗之后,控制器会定时的复位,为了防止不停的复位,就要进行“喂狗”操作,喂狗操作相对比较简单,只要在WTCNT里的计数减为0之前,将其值重置一个非0的数值即可,看下面的函数:feed_dog(该代码仅供读者参考,光盘源码中没有给出具体例子)

[plain]  view plain  copy
  1. @ 喂狗程序  
  2.   
  3. .text  
  4. .global _start  
  5.   
  6. feed_dog:  
  7.   
  8.            ldr r0, =WTCNT  
  9.   
  10.            ldr r1, =0x2710  
  11.   
  12.            str r1, [r0]  
  13.   
  14.            mov pc, lr  

喂狗程序对喂狗的时机必须要合适,否则在定时器还没来得及发生中断调用watchdog已经超时了,也将引起系统复位重启,通常系统里会开启另外一个时钟来为整个系统服务,它会定时的“告知”系统,在看门狗定时器超时之前,自动的调用喂狗程序。


总结:这篇文章讲了看门狗的一些内容,包括看门狗的作用,看门狗的分类,看门狗的工作原理和在arm处理器中看门狗的 配置手册,并根据手册计算了看门狗的计时间隔和计时周期,最后用了一些例子演示了看门狗的操作过程。后面我们将继续根据uboot启动流程讲解中断相关的知识。




转载请声明!

猜你喜欢

转载自blog.csdn.net/Qinus/article/details/84797449