Tiny4412中断之看门狗
一:看门狗(WDT watch dog timer)
看门狗其实是一个计数器,它的作用就是防止程序陷入死循环或者程序运行跑飞;看门狗是一个硬件,它的工作原理是,初始化给他一个值,它会过一段时间减一,直到这个数减为0,它将会产生一个中断信号或者reset信号,致使我们系统复位,而又时候我们不想让它过一会儿就重启又想预防死机,那么我们就可以在这个数减到快要接进0的时候,给它重新赋值;这样就不会触发reset信号,但当程序跑飞时机器死机时,它就会减到零,进行操作系统复位;
具体看下图所示:输入时钟为PCLK(该时钟频率等于系统的主频),它经过两级分频(Prescaler和frequency division factor),最后将分频后的时钟作为该定时器的输入时钟,当计数器期满后可以产生中断或者复位信号。
看门狗计数器公式如下:
t_watchdog = 1/( PCLK / (Prescaler value + 1) / Division_factor )
通过tiny4412用户手册我们可以找到看门狗的中断号为75(如下图):
预分频器Prescaler及分频因子Division factor的值在WTCON(看门狗时钟控制寄存器)中设置,如下图:
今天的程序是使用watchdog来实现led灯的闪烁,下面贴出代码:
1 #ifndef __BUNFLY_H 2 #define __BUNFLY_H 3 4 #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000) 5 #define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004) 6 #define ICDDCR (*(volatile unsigned long *)0x10490000) 7 #define ICDIPR0_CPU0 (*(volatile unsigned long *)0x10490400) 8 #define ICDIPTR0_CPU0 (*(volatile unsigned long *)0x10490800) 9 #define ICDISER0_CPU0 (*(volatile unsigned long *)0x10490100) 10 #define ICDSGIR (*(volatile unsigned long *)0x10490f00) 11 #define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) 12 #define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000c) 13 #define ICDIPR2_CPU0 (*(volatile unsigned long *)0x10490408) 14 #define ICDIPTR2_CPU0 (*(volatile unsigned long *)0x10490808) 15 #define ICDIPR3_CPU0 (*(volatile unsigned long *)0x1049040c) 16 #define ICDIPTR3_CPU0 (*(volatile unsigned long *)0x1049080c) 17 #define ICDIPR16_CPU0 (*(volatile unsigned long *)0x10490440) 18 #define ICDIPTR16_CPU0 (*(volatile unsigned long *)0x10490840) 19 #define ICDIPR18_CPU0 (*(volatile unsigned long *)0x10490448) 20 #define ICDIPTR18_CPU0 (*(volatile unsigned long *)0x10490848) 21 #define ICDISER2_CPU0 (*(volatile unsigned long *)0x10490108) 22 23 #define WTCON (*(volatile unsigned long *)0x10060000) 24 #define WTDAT (*(volatile unsigned long *)0x10060004) 25 #define WTCNT (*(volatile unsigned long *)0x10060008) 26 #define WTCLRINT (*(volatile unsigned long *)0x1006000C) 27 28 #define EXT_INT43CON (*(volatile unsigned long *)0x11000e0c) 29 #define EXT_INT43_MASK (*(volatile unsigned long *)0x11000f0c) 30 #define EXT_INT43_PEND (*(volatile unsigned long *)0x11000f4c) 31 #define GPX3CON (*(volatile unsigned long *)0x11000c60) 32 33 #define GPM4CON (*(volatile unsigned long *)0x110002e0) 34 #define GPM4DAT (*(volatile unsigned long *)0x110002e4) 35 36 #endif //__BUNFLY_H
1 #include "bunfly.h" 2 3 void (*udelay)(int) = 0xc3e25f90; 4 int (*printf)(char *, ...) = 0xc3e114d8; 5 void enable_mmu(); 6 void init_table(unsigned long *addr); 7 void memcpy(unsigned char *dest, unsigned char *src, int len); 8 extern unsigned long vector_start; 9 void do_irq(); 10 void led_on(); 11 void led_off(); 12 13 int main() 14 { 15 memcpy(0x70000000, vector_start, 0x1000); 16 enable_mmu(); 17 18 *(unsigned long *)0x47000000 = do_irq; 19 20 //step 1: set cpu permit interrupt 21 __asm__ __volatile__( 22 "mrs r0, cpsr\n" 23 "bic r0,r0, #0x80\n" 24 "msr cpsr, r0\n" 25 :::"r0" 26 ); 27 28 //step 2: set GIC (cgi) enable 29 ICCICR_CPU0 = 1; //中断总开关 30 ICCPMR_CPU0 =0xff;//设置最低优先级(门槛) 31 ICDDCR = 1; //本中断开关 32 ICDIPR18_CPU0 = (100 << 24);//设置本中断优先级 33 ICDIPTR18_CPU0 = (1 << 24);//选择指定的cpu进行中断处理 34 ICDISER2_CPU0 = (1 << 11);//启用本中断 35 36 //step 3: set watch dog timer 37 WTCNT = 32768; 38 WTDAT = 32768; 39 WTCON = (1 << 2) | (3 << 3) | (1 << 5) | (95 << 8); 40 41 printf("welcom back\n"); 42 } 43 44 void do_irq() 45 { 46 WTCLRINT = 0;//清中断 47 printf("wang wang wang\n"); 48 static int flags = 1; 49 if(flags) { 50 led_on(); 51 flags = 0; 52 } 53 else { 54 led_off(); 55 flags = 1; 56 } 57 } 58 59 void led_on() 60 { 61 GPM4CON &= ~0xffff; 62 GPM4CON |= 0x1111; 63 GPM4DAT &= ~0xf; 64 } 65 66 void led_off() 67 { 68 69 GPM4CON &= ~0xffff; 70 GPM4CON |= 0x1111; 71 GPM4DAT |= 0xf; 72 } 73 74 void memcpy(unsigned char *dest, unsigned char *src, int len) 75 { 76 int i = 0; 77 for(i = 0; i < len; i++) { 78 dest[i] = src[i]; 79 } 80 } 81 82 void enable_mmu() 83 { 84 /*构建表*/ 85 unsigned long addr = 0x50000000; 86 init_table(addr); 87 /*打开mmu*/ 88 unsigned long mmu = 0; 89 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8); 90 __asm__ __volatile__ ( 91 "mov r0, #3\n" 92 "MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员 93 "MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址 94 "MCR p15, 0, %1, c1, c0, 0\n"//开启mmu 95 : 96 : "r" (addr), "r" (mmu) 97 : 98 ); 99 100 } 101 102 __asm__( 103 104 "vector: \n" 105 " b reset\n" 106 " b und\n" 107 " b swi\n" 108 " b pre_abt\n" 109 " b data_abt\n" 110 " .word 0x0\n" 111 " b irq\n" 112 " b fiq\n" 113 "reset:\n" 114 "und:\n" 115 " mov sp, #0x47000000\n" 116 " stmdb sp!, {r0-r12, lr}\n" 117 118 " ldr r3, =0x47000004\n" 119 " ldr r2, [r3]\n" 120 " blx r2\n" 121 122 " mov sp, #0x47000000\n" 123 " ldmdb sp, {r0-r12, pc}^ \n" 124 125 "swi:\n" 126 " mov sp, #0x47000000\n" 127 " stmdb sp!, {r0-r12, lr}^\n" 128 129 " mov sp, #0x47000000\n" 130 " ldmdb sp, {r0-r12, pc}^ \n" 131 132 "pre_abt:\n" 133 134 "data_abt:\n" 135 " mov sp, #0x47000000\n" 136 " sub lr, lr, #4\n" 137 " stmdb sp!, {r0-r12, lr}\n" 138 139 " ldr r3, =0x47000008\n" 140 " ldr r2, [r3]\n" 141 " blx r2\n" 142 143 " mov sp, #0x47000000\n" 144 " ldmdb sp, {r0-r12, pc}^ \n" 145 "irq:\n" 146 147 " mov sp, #0x47000000\n" 148 " sub lr, lr, #4\n" 149 " stmdb sp!, {r0-r12, lr}\n" 150 151 " ldr r3, =0x47000000\n" 152 " ldr r2, [r3]\n" 153 " blx r2\n" 154 155 " mov sp, #0x47000000\n" 156 " ldmdb sp, {r0-r12, pc}^ \n" 157 158 "fiq:\n" 159 160 ".global vector_start\n" 161 "vector_start: \n" 162 ".word vector \n " 163 164 ); 165 166 void init_table(unsigned long *addr) 167 { 168 unsigned long va = 0; 169 unsigned long phys = 0; 170 171 //0x40000000-0x80000000 -> 0x40000000-0x80000000 172 for(va = 0x40000000; va < 0x80000000; va += 0x100000) { 173 phys = va; 174 addr[va >> 20] = phys | 2; 175 } 176 177 //0x10000000-0x14000000 -> 0x10000000-0x140000000 178 for(va = 0x10000000; va < 0x14000000; va += 0x100000) { 179 phys = va; 180 addr[va >> 20] = phys | 2; 181 } 182 //0x10000000-0x14000000 -> 0x10000000-0x140000000 183 for(va = 0x0; va < 0x10000000; va += 0x100000) { 184 phys = va + 0x70000000; 185 addr[va >> 20] = phys | 2; 186 } 187 188 }