ARM中的看门狗程序

在ARM中,有一个硬件部分叫WATCH DOG。这个硬件,一直在做一件事情:就是,从某一数值,一直数,各一段时间减一,隔一段时间减一,直到减到0的时候将会触发重启或者中断。而有时候,为了预防死机,我们在操作系统跑起来的时候会有一个特定的程序来做一件事情:减到特定是值的时候数值将会重新置到100.这样,看门狗将会循环往复做一件事情:一直数数,而不会死机。

这个程序叫做守护程序:又叫做喂狗程序。

看门狗的逻辑运算图如下:

今天,有看门狗来写了一个程序:隔一段时间来触发一个中断,每次中断来的时候,将会让板子上面的灯和蜂鸣器做出相应的反映:

首先:在头文件中将具体的寄存器声明:

 1 
  2 #define gpiobase        0x11000000
  3 #define GPM4CON         (*(volatile unsigned long *)(gpiobase + 0x02E0)) 
  4 #define GPM4DAT         (*(volatile unsigned long *)(gpiobase + 0x02E4))
  5 #define GPX3CON         (*(volatile unsigned long *)(gpiobase + 0x0C60))
  6 #define GPX3DAT         (*(volatile unsigned long *)(gpiobase + 0x0C64))
  7 #define GPD0CON         (*(volatile unsigned long *)(gpiobase + 0x4000A0))
  8 #define GPD0DAT         (*(volatile unsigned long *)(gpiobase + 0x4000A4))
  9 
 10 #define ICC 0x10480000
 11 
 12 #define ICCICR_CPU0     (*(volatile unsigned long *)(ICC + 0x0000)) 
 13 #define ICCPMR_CPU0     (*(volatile unsigned long *)(ICC + 0x0004)) 
 14 #define ICCBPR_CPU0     (*(volatile unsigned long *)(ICC + 0x0008)) 
 15 #define ICCIAR_CPU0     (*(volatile unsigned long *)(ICC + 0x000C)) 
 16 #define ICCEOIR_CPU0    (*(volatile unsigned long *)(ICC + 0x0010)) 
 17 #define ICCRPR_CPU0     (*(volatile unsigned long *)(ICC + 0x0014)) 
 18 #define ICCHPIR_CPU0    (*(volatile unsigned long *)(ICC + 0x0018)) 
 19 #define ICCABPR_CPU0    (*(volatile unsigned long *)(ICC + 0x001C)) 
 20 #define INTEG_EN_C_CPU0 (*(volatile unsigned long *)(ICC + 0x0040)) 
 21 #define ICCIIDR         (*(volatile unsigned long *)(ICC + 0x00FC))
 22 
 23 #define ICD 0x10490000
 24 
 25 #define ICDDCR            (*(volatile unsigned long *)(ICD + 0x0000))
 26 #define ICDICTR           (*(volatile unsigned long *)(ICD + 0x0004))
 27 #define ICDIIDR           (*(volatile unsigned long *)(ICD + 0x0008))
 28 #define ICDISR0_CPU0      (*(volatile unsigned long *)(ICD + 0x0080))
 29 #define ICDISER0_CPU0     (*(volatile unsigned long *)(ICD + 0x0100))
 30 #define ICDISER2_CPU0     (*(volatile unsigned long *)(ICD + 0x0108))
 31 #define ICDICER0_CPU0     (*(volatile unsigned long *)(ICD + 0x0180))
 32 #define ICDISPR0_CPU0     (*(volatile unsigned long *)(ICD + 0x0200))
 33 #define ICDICPR0_CPU0     (*(volatile unsigned long *)(ICD + 0x0280))
 34 #define ICDABR0_CPU0      (*(volatile unsigned long *)(ICD + 0x0300))
 35 #define ICDIPR0_CPU0      (*(volatile unsigned long *)(ICD + 0x0400))
 36 #define ICDIPR1_CPU0      (*(volatile unsigned long *)(ICD + 0x0404))
 37 #define ICDIPR2_CPU0      (*(volatile unsigned long *)(ICD + 0x0408))
 38 #define ICDIPR3_CPU0      (*(volatile unsigned long *)(ICD + 0x040C))
 39 #define ICDIPR4_CPU0      (*(volatile unsigned long *)(ICD + 0x0410))
 40 #define ICDIPR5_CPU0      (*(volatile unsigned long *)(ICD + 0x0414))
 41 #define ICDIPR6_CPU0      (*(volatile unsigned long *)(ICD + 0x0418))
 42 #define ICDIPR7_CPU0      (*(volatile unsigned long *)(ICD + 0x041C))
 43 #define ICDIPR18_CPU0      (*(volatile unsigned long *)(ICD + 0x448))
 44 
 45 #define ICDIPTR0_CPU0   (*(volatile unsigned long *)(ICD + 0x0800))
 46 #define ICDIPTR1_CPU0   (*(volatile unsigned long *)(ICD + 0x0804))
 47 #define ICDIPTR18_CPU0  (*(volatile unsigned long *)(ICD + 0x0848))
 48 #define ICDSGIR     (*(volatile unsigned long *)(ICD + 0x0F00))
 49 
 50 
 51 #define WTCON    (*(volatile unsigned long *)0x10060000)
 52 #define WTDAT    (*(volatile unsigned long *)0x10060004)
 53 #define WTCNT    (*(volatile unsigned long *)0x10060008)
 54 #define WTCLRINT (*(volatile unsigned long *)0x1006000C) 
 55 
 56 
 57 

在主要的文件中:

  1 #include"regs.h"
  2 
  3 int (*printf)(char *, ...) = 0xc3e114d8;
  4 int(*delay)(int)=0xc3e25f90;
  5 
  6 void init_ttb(unsigned long *addr);
  7 void enable_mmu(void);
  8 unsigned long data_abort_init();
  9 void memcopy(unsigned long* dest,unsigned long* source,int len);
 10 void do_irq();
 11 void pwm_on(void);
 12 void pwm_off(void);
 13 void led_on(void);
 14 void led_on(void);
 15 
 16 
 17 
 18 int main()
 19 {
 20      *(unsigned long *)0x66000000 = do_irq;
 21 
 22     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   
 23     unsigned long source_addr=data_abort_init();
 24     //异常事件处理函数
 25     printf("swi_souce addr is %x
",source_addr);
 26     //将异常处理地址的值放到0x60000004
 27     memcopy(0x60000000,source_addr,0x1000);
 28 
 29     enable_mmu();
 30     //内存映射将0x00000004映射到0x6000000004    
 31 
 32      //step 1: cpu cpsr
 33       __asm__ __volatile__(
 34           "mrs r0, cpsr
"
 35           "bic r0, r0, #0x80
"//设置CPSR的I位,将IRQ位打开
 36           "msr cpsr, r0
"
 37           ::: "r0"
 38       );
 39 
 40       //step 2: GIC 
 41       ICCICR_CPU0 = 1;//CPU接口控制寄存器
 42       ICCPMR_CPU0 = 0xff;//中断优先标志寄存器
 43 
 44      //75
 45      ICDDCR = 1;
 46      //ICDIPR0_CPU0 = (0x00 << 0);
 47      ICDIPR18_CPU0 = (0x0 << 24);
 48      //ICDIPTR0_CPU0 = 1;
 49      ICDIPTR18_CPU0 = (0x1 << 24);
 50      //ICDISER0_CPU0 = (1 << 0);
 51      ICDISER2_CPU0 = (1 << 11);
 52 
 53      //step 3: interrupt source watchdog
 54      WTCON = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (250 << 8);
 55      WTCNT = 0x8000;
 56      WTDAT = 0x1000;
 57 
 58     printf("welcome back! 
");
 59 
 60 
 61 }
 62 
 63 void pwm_on(void)
 64     {
 65         GPD0CON &= ~0xffff;
 66         GPD0CON |= 0x1;//配置寄存器为2
 67         GPD0DAT |= 0x1;//date=0xf
 68     }
 69 
 70 void pwm_off(void)
 71     {
 72         GPD0CON &= ~0xffff;
 73         GPD0CON |= 0x0;
 74     //  GPD0DAT &=0x0 ;//date=0xf
 75 
 76     }
 77 void led_off(void)
 78     {
 79         GPM4CON &= ~0xffff;//清零
 80         GPM4CON |= 0x0000;//0---3位清零
 81         GPM4DAT |= 0x0;//date=0xf关闭置一
 82     }
83 void led_on(void)
 84     {
 85         GPM4CON &= ~0xffff;
 86         GPM4CON |= 0x1111;//配置寄存器3-0-----3-3全为1111,全为输出模式
 87         GPM4DAT &= ~0xf;//打开置0-4位为0000
 88     }
 89 
 90 void do_irq()
 91     {
 92         unsigned long data = ICCIAR_CPU0;
 93         unsigned long irq_id = data & 0x3ff;
 94         unsigned long cpu_id = (data >> 10) & 0x7;
 95         ICCEOIR_CPU0 = irq_id | (cpu_id << 10);
 96         printf("irq is %d, cpu is %d
", irq_id, cpu_id);
 97 
 98          pwm_on();
 99          led_on();
100         printf("hello dog!
");
101          delay(6000000);
102          pwm_off();
103          led_off();
104         WTCLRINT = 0x1;
105     }
106 
107 void memcopy(unsigned long* dest, unsigned long* source,int len)
108 {
109     int i=0;;
110     for(i=0;i<len;i++)
111         dest[i]=source[i];
112 }
113 
114 unsigned long  data_abort_init()
115 {
116     unsigned long source;
117     __asm__ __volatile__(
118          "ldr %0, =voliate_start
"
119          : "=r" (source)
120      );
121 
122 
123     return source;
124 
125 }
126 
127 __asm__(
128 
129 "voliate_start:
"
130     //跳转目录
131     " b reset
"
132     " b undefined
"
133     " b swi
"
134     " b pre_abt
"
135     " b data_abt
"
136     " .word 0
"//占位符号,一个位占4个字节
137     " b irq
"
138     " b fiq
"
139 "
"
140 
141     //跳转要分三部:
142     //1:将PC保存到新模式下的lr中;
143     //2:将CPSR保存在SPSR中
144     //3:初始化SP
145     //前两步由硬件完成,而第三部需要手动完成
146 "reset:
"
147 
148 "undefined:
"
149      "mov sp, #0x66000000
"//初始化SP
150      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
151     //打印一句话 
152      "ldr r0, =und_string
"
153      "ldr r2, show
"
154      "blx r2
"
155     //跳回来分两部
156     //1:将CPSR保存在SPSR中
157     //2:将PC保存到新模式下的lr中;
158      "mov sp, #0x66000000
"//
159      "ldmea sp, {r0-r12, pc}^
"// 
160 
 161 "swi:
"
162 
163 "pre_abt:
"
164 "data_abt:
"
165      "sub lr, lr, #4
"
166      "mov sp, #0x66000000
"//初始化SP
167      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
168     //打印一句话 
169      "ldr r0, =data_string
"
170      "ldr r2, show
"
171      "blx r2
"
172     //跳回来分两部
173     //1:将CPSR保存在SPSR中
174     //2:将PC保存到新模式下的lr中;
175      "mov sp, #0x66000000
"//
176      "ldmea sp, {r0-r12, pc}^
"// 
177 
178 "irq:
"
179     "sub lr, lr, #4
"
180      "mov sp, #0x66000000
"//初始化SP
181      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
182     //打印一句话 
183      "mov r2, #0x66000000
"
184      "ldr r1, [r2]
"
185      "blx r1
"
186 
187    //  "ldr r0, =irq_string
"
188    //  "ldr r2, show
"
189    //  "blx r2
"
190     //跳回来分两部
191     //1:将CPSR保存在SPSR中
192     //2:将PC保存到新模式下的lr中;
193      "mov sp, #0x66000000
"//
194      "ldmea sp, {r0-r12, pc}^
"//
195 "fiq:
"
196     "show:
"
197      ".word 0xc3e114d8
"
198 
199     "und_string:
"
200      ".asciz "This is  UND!\n" 
"
201      "data_string:
"
202      ".asciz "This DATA_ABORT!\n" 
"
203      "irq_string:
"
204      ".asciz "This IRQ!\n" 
"
205 
206         );
207 
208 void init_ttb(unsigned long *addr)
209 {
210     unsigned long va = 0;//定义虚拟地址
211     unsigned long pa = 0;//定义物理地址
212 
213     //40000000-------80000000   ====  40000000------80000000
214     for(va=0x40000000; va<=0x80000000; va+=0x100000){
215         pa = va;
216         addr[va >> 20] = pa | 2;
217         //|2的目的是将0-2位置为10此时将是小页模式4K
218     }
219 
220     //00000000-------10000000   ====  60000000------70000000
221     for(va=0x00000000; va<=0x10000000; va+=0x100000){
222         pa = va+0x60000000;
223         addr[va >> 20] = pa | 2;
224     }
225 
226     //10000000-------14000000   ====  10000000------14000000
227     for(va=0x10000000; va<=0x14000000; va+=0x100000){
228         pa = va;
229         addr[va >> 20] = pa | 2;
230     }
231 
232     //30000000-------40000000   ====  50000000------60000000
233     for(va=0x30000000; va<0x40000000; va+=0x100000){
234         pa = va + 0x20000000;
235         addr[va >> 20] = pa | 2;
236     }
237 }
                                                                  

主要看主函数部分:

39
 40       //step 2: GIC
 41       ICCICR_CPU0 = 1;//CPU接口控制寄存器
 42       ICCPMR_CPU0 = 0xff;//中断优先标志寄存器
 43
 44      //75
 45      ICDDCR = 1;
 46      //ICDIPR0_CPU0 = (0x00 << 0);
 47      ICDIPR18_CPU0 = (0x0 << 24);
 48      //ICDIPTR0_CPU0 = 1;
 49      ICDIPTR18_CPU0 = (0x1 << 24);
 50      //ICDISER0_CPU0 = (1 << 0);
 51      ICDISER2_CPU0 = (1 << 11);
 52
 53      //step 3: interrupt source watchdog
 54      WTCON = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (250 << 8);
 55      WTCNT = 0x8000;
 56      WTDAT = 0x1000;
 57
 58     printf("welcome back! ");
还有:

90 void do_irq()
 91     {
 92         unsigned long data = ICCIAR_CPU0;
 93         unsigned long irq_id = data & 0x3ff;
 94         unsigned long cpu_id = (data >> 10) & 0x7;
 95         ICCEOIR_CPU0 = irq_id | (cpu_id << 10);
 96         printf("irq is %d, cpu is %d ", irq_id, cpu_id);
 97
 98          pwm_on();
 99          led_on();
100         printf("hello dog! ");
101          delay(6000000);
102          pwm_off();
103          led_off();
104         WTCLRINT = 0x1;
105     }
其中,各个寄存器详见:1352芯片手册。

运行成功:

将会发现板子,各一段时间就会叫一次。LED会闪烁一次!

改变WTDAT的值就会修改叫的频率!

原文地址:https://www.cnblogs.com/hongzhunzhun/p/4513072.html