一:外部中断
在之前我们学习按键驱动的时候,我们检测按键有没有按下是通过轮循的方式(也就是我们说的死循环),这样虽然可以检测实现按键,但太浪费系统资源了,不论我们按键中断有没有发生,cpu都要一直进行检测;这样操作系统就不能做其他事情了,因此这样肯定是不可取得,因此我们可以通过外部中断解决它;
要处理一个中断,我们需要了解模式,而了解模式,有需要了解mmu;在学习这些之后我们就可以返回来处理我们按键驱动的时候留下的问题了;
通过之前的按前驱动我们已经了解了按前驱动在板子上的位置以及按键的电路图以及他的引脚作用,下面我们就如何实现这个程序的步骤:
我们知道控制按键的寄存器为:
外部中断对应的是:
0xf = EXT_INT43[2]
在EXT_INT43[2]中我们选择边沿触发方式:
通过key在核心板的引脚图我们可以知道外部中断源为26,中断号为64
需要我们配置的寄存器:
(1) EXT_INT43PEND (2)EXT_INT43MASK (3)EXT_INT43CON
需要注意的是:中断状态:EXT_INT43_PEND[2],特别注意的是,要清中断,将值赋值为1.
实现一个外部中断大致需要五步:
(1)cpu允许中断
(2)启用GIC
(3)配置外部中断寄存器(xeint)
(4)配置gpio(General Purpose Input Output (通用输入/输出)简称为GPIO,每个GPIO端口可通过软件分别配置成输入或输出)
(5)外部中断源
下面是实现的具体代码:
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_INT43_CON (*(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 int (*printf)(char *, ...) = 0xc3e114d8; 4 void enable_mmu(); 5 void init_table(unsigned long *addr); 6 void memcpy(unsigned char *dest, unsigned char *src, int len); 7 extern unsigned long vector_start; 8 void do_irq(); 9 10 int main() 11 { 12 memcpy(0x70000000, vector_start, 0x10000); 13 enable_mmu(); 14 15 *(unsigned long *)0x47000000 = do_irq; 16 17 //step 1: cpu permit interrupt 18 __asm__ __volatile__ ( 19 "mrs r0, cpsr\n" 20 "bic r0, r0, #0x80\n" 21 "msr cpsr, r0\n" 22 ::: "r0" 23 ); 24 25 //step 2: GIC (cgi) enable 26 ICCICR_CPU0 = 1;//总开关 27 ICCPMR_CPU0 = 0xff;//总优先级(门槛) 28 ICDDCR = 1; //本中断开关 29 30 ICDIPR16_CPU0 = (0 << 0); //本中断优先级 31 ICDIPTR16_CPU0 = (1 << 0); //目标cpu 32 ICDISER2_CPU0 = (1 << 0); //启用本中断 33 34 //step 3: Xeint 35 EXT_INT43_CON = (4 << 8);//Triggers Both edge (设置为边沿触发) 36 EXT_INT43_MASK = 0; //开启中断 37 38 //step 4: set gpio 39 GPX3CON = (0xf << 8); //0xF = EXT_INT43[2] (gpio配置为外部中断)
40 41 //step 5: interrupt source 42 43 printf("welcome back\n"); 44 } 45 46 void do_irq() 47 { 48 unsigned long data = ICCIAR_CPU0; 49 int irq = data & 0x3ff; //获得中断号 50 int cpu = (data >> 10) & 0x7; //获得目标cpu 51 ICCEOIR_CPU0 = irq | (cpu << 10); //清除中断 52 EXT_INT43_PEND |= (1 << 2); //清中断 53 printf("key 1 down, cpu is %d, irq is %d\n", cpu, irq); 54 } 55 56 void enable_mmu() 57 { 58 unsigned long addr = 0x50000000; 59 init_table(addr); 60 unsigned long mmu = 0; 61 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8); 62 63 __asm__ __volatile__ ( 64 "mov r0, #3\n" 65 "MCR p15, 0, r0, c3, c0, 0\n" 66 "MCR p15, 0, %0, c2, c0, 0\n" 67 "MCR p15, 0, %1, c1, c0, 0\n" 68 : 69 : "r" (addr), "r" (mmu) 70 : 71 ); 72 } 73 74 void init_table(unsigned long *addr) 75 { 76 unsigned long va = 0; 77 unsigned long phys = 0; 78 79 for(va = 0x40000000; va < 0x80000000; va+=0x100000) 80 { 81 phys = va; 82 addr[va >> 20] = phys | 2; 83 } 84 85 for(va = 0x10000000; va < 0x14000000; va+=0x100000) 86 { 87 phys = va; 88 addr[va >> 20] = phys | 2; 89 } 90 91 for(va = 0x0; va < 0x10000000; va+=0x100000) 92 { 93 phys = va + 0x70000000; 94 addr[va >> 20] = phys | 2; 95 } 96 } 97 98 __asm__ ( 99 "vector:\n" 100 " b reset\n" 101 " b undefined\n" 102 " b swi\n" 103 " b pre_abt\n" 104 " b data_abt\n" 105 " .word 0x0\n" 106 " b irq\n" 107 " b fiq\n" 108 109 "reset:\n" 110 "undefined:\n" 111 " mov sp, #0x47000000\n" 112 " stmdb sp!, {r0-r12, lr}\n" 113 114 "ldr r3, =0x47000004\n" 115 "ldr r2, [r3]\n" 116 "blx r2\n" 117 118 " mov sp, #0x47000000\n" 119 " ldmdb sp, {r0-r12, pc}^\n" 120 "swi:\n" 121 " mov sp, #0x47000000\n" 122 " stmdb sp!, {r0-r12, lr}\n" 123 124 " mov sp, #0x47000000\n" 125 " ldmdb sp, {r0-r12, pc}^\n" 126 "pre_abt:\n" 127 "data_abt:\n" 128 " mov sp, #0x47000000\n" 129 " sub lr, lr, #4\n" 130 " stmdb sp!, {r0-r12, lr}\n" 131 132 "ldr r3, =0x47000008\n" 133 "ldr r2, [r3]\n" 134 "blx r2\n" 135 136 " mov sp, #0x47000000\n" 137 " ldmdb sp, {r0-r12, pc}^\n" 138 "irq:\n" 139 " mov sp, #0x47000000\n" 140 " sub lr, lr, #4\n" 141 " stmdb sp!, {r0-r12, lr}\n" 142 143 "mov r3, #0x47000000\n" 144 "ldr r2, [r3]\n" 145 "blx r2\n" 146 147 " mov sp, #0x47000000\n" 148 " ldmdb sp, {r0-r12, pc}^\n" 149 "fiq:\n" 150 151 ".global vector_start\n" 152 "vector_start:\n" 153 ".word vector\n" 154 ); 155 156 void memcpy(unsigned char *dest, unsigned char *src, int len) 157 { 158 int i = 0; 159 for(i = 0; i < len; i++) 160 dest[i] = src[i]; 161 }
下面我们通过外部中断(KEY1)控制watchdog,在通过watchdog控制led灯,当key1按下时,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_INT43_CON (*(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 void wdt_on(); 13 void wdt_off(); 14 15 int main() 16 { 17 memcpy(0x70000000, vector_start, 0x1000); 18 enable_mmu(); 19 20 *(unsigned long *)0x47000000 = do_irq; 21 22 //step 1: cpu permit interrupt 23 __asm__ __volatile__( 24 "mrs r0, cpsr\n" 25 "bic r0,r0, #0x80\n" 26 "msr cpsr, r0\n" 27 :::"r0" 28 ); 29 30 //step 2: GIC (cgi) enable 31 ICCICR_CPU0 = 1; //总开关 32 ICCPMR_CPU0 =0xff;//总优先级 33 ICDDCR = 1; //本中断开关 34 35 //KEY 36 ICDIPR16_CPU0 = (1 << 0);//本中断优先级 37 ICDIPTR16_CPU0 = (1 << 0);//目标cpu 38 ICDISER2_CPU0 = (1 << 0);//启用本中断 39 40 //WDT 41 ICDIPR18_CPU0 = (1 << 24); 42 ICDIPTR18_CPU0 = (1 << 24); 43 ICDISER2_CPU0 = (1 << 11); 44 45 //step 3: Xeint 46 EXT_INT43_CON = (0x2 << 8); 47 EXT_INT43_MASK = 0; 48 49 //step 4: set gpio 50 GPX3CON = (0xf << 8); 51 52 //step 5: interrupt source 53 54 printf("welcom back\n"); 55 56 } 57 58 void do_irq() 59 { 60 unsigned long data = ICCIAR_CPU0; 61 int irq = data & 0x3ff; 62 int cpu = (data >> 10) & 0x7; 63 ICCEOIR_CPU0 = irq | (cpu << 10); 64 static int flags = 1; 65 66 if(64 == irq) { 67 printf("key 1 down\n"); 68 if(EXT_INT43_PEND & (0x1 << 2)) { 69 EXT_INT43_PEND |= (1 << 2); 70 if(flags) { 71 wdt_on(); 72 flags = 0; 73 } 74 else { 75 wdt_off(); 76 led_off(); 77 flags = 1; 78 } 79 } 80 } 81 82 if(75 == irq) { 83 WTCLRINT = 0;//清中断 84 printf("wang wang wang ...\n"); 85 if(flags) { 86 led_on(); 87 flags = 0; 88 } 89 else { 90 led_off(); 91 flags = 1; 92 } 93 } 94 } 95 96 void led_on() 97 { 98 GPM4CON &= ~0xffff; 99 GPM4CON |= 0x1111; 100 GPM4DAT &= ~0xf; 101 } 102 103 void led_off() 104 { 105 106 GPM4CON &= ~0xffff; 107 GPM4CON |= 0x1111; 108 GPM4DAT |= 0xf; 109 } 110 111 void wdt_on() 112 { 113 WTCNT = 0x8000; 114 WTDAT = 0x8000; 115 WTCON = 0 | (1 << 2) | (2 << 3) | (1 << 5) | (50 << 8); 116 } 117 118 void wdt_off() 119 { 120 WTCON = 0; 121 } 122 123 void memcpy(unsigned char *dest, unsigned char *src, int len) 124 { 125 int i = 0; 126 for(i = 0; i < len; i++) { 127 dest[i] = src[i]; 128 } 129 } 130 131 void enable_mmu() 132 { 133 /*构建表*/ 134 unsigned long addr = 0x50000000; 135 init_table(addr); 136 /*打开mmu*/ 137 unsigned long mmu = 0; 138 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8); 139 __asm__ __volatile__ ( 140 "mov r0, #3\n" 141 "MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员 142 "MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址 143 "MCR p15, 0, %1, c1, c0, 0\n"//开启mmu 144 : 145 : "r" (addr), "r" (mmu) 146 : 147 ); 148 149 } 150 151 __asm__( 152 153 "vector: \n" 154 " b reset\n" 155 " b und\n" 156 " b swi\n" 157 " b pre_abt\n" 158 " b data_abt\n" 159 " .word 0x0\n" 160 " b irq\n" 161 " b fiq\n" 162 "reset:\n" 163 "und:\n" 164 " mov sp, #0x47000000\n" 165 " stmdb sp!, {r0-r12, lr}\n" 166 167 " ldr r3, =0x47000004\n" 168 " ldr r2, [r3]\n" 169 " blx r2\n" 170 171 " mov sp, #0x47000000\n" 172 " ldmdb sp, {r0-r12, pc}^ \n" 173 174 "swi:\n" 175 " mov sp, #0x47000000\n" 176 " stmdb sp!, {r0-r12, lr}^\n" 177 178 " mov sp, #0x47000000\n" 179 " ldmdb sp, {r0-r12, pc}^ \n" 180 181 "pre_abt:\n" 182 183 "data_abt:\n" 184 " mov sp, #0x47000000\n" 185 " sub lr, lr, #4\n" 186 " stmdb sp!, {r0-r12, lr}\n" 187 188 " ldr r3, =0x47000008\n" 189 " ldr r2, [r3]\n" 190 " blx r2\n" 191 192 " mov sp, #0x47000000\n" 193 " ldmdb sp, {r0-r12, pc}^ \n" 194 "irq:\n" 195 196 " mov sp, #0x47000000\n" 197 " sub lr, lr, #4\n" 198 " stmdb sp!, {r0-r12, lr}\n" 199 200 " ldr r3, =0x47000000\n" 201 " ldr r2, [r3]\n" 202 " blx r2\n" 203 204 " mov sp, #0x47000000\n" 205 " ldmdb sp, {r0-r12, pc}^ \n" 206 207 "fiq:\n" 208 209 ".global vector_start\n" 210 "vector_start: \n" 211 ".word vector \n " 212 213 ); 214 215 void init_table(unsigned long *addr) 216 { 217 unsigned long va = 0; 218 unsigned long phys = 0; 219 220 //0x40000000-0x80000000 -> 0x40000000-0x80000000 221 for(va = 0x40000000; va < 0x80000000; va += 0x100000) { 222 phys = va; 223 addr[va >> 20] = phys | 2; 224 } 225 226 //0x10000000-0x14000000 -> 0x10000000-0x140000000 227 for(va = 0x10000000; va < 0x14000000; va += 0x100000) { 228 phys = va; 229 addr[va >> 20] = phys | 2; 230 } 231 //0x10000000-0x14000000 -> 0x10000000-0x140000000 232 for(va = 0x0; va < 0x10000000; va += 0x100000) { 233 phys = va + 0x70000000; 234 addr[va >> 20] = phys | 2; 235 } 236 237 }