具体如下:
处理外部中断有五个步骤:
30 //step 1: cpu cpsr
31 __asm__ __volatile__(
32 "mrs r0, cpsr\n"
33 "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开
34 "msr cpsr, r0\n"
35 ::: "r0"
36 );
37
38 //setp1:GIC
39 ICCICR_CPU0 = 1;
40 ICCPMR_CPU0 = 0xff;
41
前面的代码不解释,和以前的差不多
外部中断号为:64
42 //step2:设置中断号
43 ICDDCR = 1;//总开关
44 ICDIPR16_CPU0 = (0x0 << 0);//ICD一共40个寄存器,第16个寄存器,第0位
45 ICDIPTR16_CPU0 = (0x1 << 0);//优先级,最高
46 ICDISER2_CPU0 = (1 << 0);//一共五个,第2个使能中断
第二步为设置中断号:
详细看代码注释:寄存器参考手册第594页
48 //step 3: set gpio
49 GPX3CON = (0xf << 8);//是GPXCON为外部中断功能
查看到使用外部中断功能的对应外部寄存器:EXT_INT43:
51 //step 4: extern
52 EXT_INT43CON = (2 << 8);//设置上升沿触发
53 EXT_INT43MASK = 0;//使能中断
设置外部中断控制器:寄存器参考手册第366页
55 //step 5: source
56 外部中断源这里设置由外部按键K触发:
代码如下
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 int main() 17 { 18 *(unsigned long *)0x66 = do_irq; 19 20 //发生异常时会进入异常模式跳转到0 4地址处理异常事件 21 unsigned long source_addr=data_abort_init(); 22 //异常事件处理函数 23 printf("swi_souce addr is %x\n",source_addr); 24 //将异常处理地址的值放到0x64 25 memcopy(0x60,source_addr,0x1); 26 27 enable_mmu(); 28 //内存映射将0x04映射到0x6004 29 30 //step 1: cpu cpsr 31 __asm__ __volatile__( 32 "mrs r0, cpsr\n" 33 "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开 34 "msr cpsr, r0\n" 35 ::: "r0" 36 ); 37 38 //setp1:GIC 39 ICCICR_CPU0 = 1; 40 ICCPMR_CPU0 = 0xff; 41 42 //step1:设置中断号 43 ICDDCR = 1; 44 ICDIPR16_CPU0 = (0x0 << 0);//ICD第16个寄存器,第0位 45 ICDIPTR16_CPU0 = (0x1 << 0);//优先级,最高 46 ICDISER2_CPU0 = (1 << 0);//一共五个,第2个使能中断 47 48 //step 3: set gpio 49 GPX3CON = (0xf << 8);//是GPXCON为外部中断功能 50 51 //step 4: extern 52 EXT_INT43CON = (2 << 8);//设置上升沿触发 53 EXT_INT43MASK = 0;//使能中断 54 55 //step 5: source 56 // 57 printf("welcome back! \n"); 58 } 59 60 void pwm_on(void) 61 { 62 GPD0CON &= ~0xffff; 63 GPD0CON = 0x1;//配置寄存器为2 64 GPD0DAT = 0x1;//date=0xf 65 } 66 67 void pwm_off(void) 68 { 69 GPD0CON &= ~0xffff; 70 GPD0CON = 0x0; 71 // GPD0DAT &=0x0 ;//date=0xf 72 73 } 74 void led_off(void) 75 { 76 GPM4CON &= ~0xffff;//清零 77 GPM4CON = 0x0;//03位清零 78 GPM4DAT = 0x0;//date=0xf关闭置一 79 } 80 void led_on(void) 81 { 82 GPM4CON &= ~0xffff; 83 GPM4CON = 0x1;//配置寄存器3-0--3-3全为1,全为输出模式 84 GPM4DAT &= ~0xf;//打开置0-4位为0 85 } 86 87 void do_irq() 88 { 89 printf("key 1 down\n"); 90 static int flag=1; 91 if(flag) 92 { 93 printf("wtc_on\n"); 94 led_on(); 95 pwm_on(); 96 flag=0; 97 } 98 else if(flag == 0) 99 { 100 printf("wtc_off\n"); 101 led_off(); 102 pwm_off(); 103 flag=1; 104 } 105 EXT_INT43PEND = (1 << 2);//清中断 106 } 107 108 void memcopy(unsigned long* dest, unsigned long* source,int len) 109 { 110 int i=0;; for(i=0;i> 20] = pa 2; 210 //2的目的是将0-2位置为10此时将是小页模式4K 211 } 212 213 //00-10 ==== 6070 214 for(va=0x00; va<=0x10; va+=0x100){ 215 pa = va+0x60; 216 addr[va >> 20] = pa 2; 217 } 218 219 //10-14 ==== 1014 220 for(va=0x10; va<=0x14; va+=0x100){ 221 pa = va; addr[va >> 20] = pa 2; 223 } 224 225 //30-40 ==== 5060 226 for(va=0x30; va<0x40; va+=0x100){ 227 pa = va + 0x20; 228 addr[va >> 20] = pa 2; 229 } 230 } 231 232 void enable_mmu(void) 233 234 { 235 unsigned long addr = 0x70; 236 init_ttb(addr); 237 //step:初始化页表 238 239 unsigned long mmu = 1 (1 << 1) (1 << 8); 240 //将MMU的第0,1,8位置1 241 __asm__ __volatile__( 242 "mov r0, #3\n" 243 "MCR p15, 0, r0, c3, c0, 0\n"//manager 244 "MCR p15, 0, %0, c2, c0, 0\n"//addr 245 "MCR p15, 0, %1, c1, c0, 0\n"// enable mmu 246 : 247 : "r" (addr), "r" (mmu) 248 : "r0" 249 ); 250 printf("MMU is enable!\n"); 251 } 252 253 254
需要注意的是:在do_irq()函数中有一个清中断的操作,否则,将会告诉中断控制器处理好了中断,以免一直触发外部中断:
87 void do_irq()
88 {
89 printf("key 1 down\n");
90 static int flag=1;
91 if(flag)
92 {
93 printf("wtc_on\n");
94 led_on();
95 pwm_on();
96 flag=0;
97 }
98 else if(flag == 0)
99 {
100 printf("wtc_off\n");
101 led_off();
102 pwm_off();
103 flag=1;
104 }
105
EXT_INT43PEND = (1 << 2);//清中断
106 }
当程序运行成功了之后,按下按键,LED和蜂鸣器就会工作,再按下按键,LED和蜂鸣器就会停止!
接下来,将以前的中断问题综合起来:写了一个用外部中断来控制LED灯闪烁的例子
流程图是:
主要是do_rirq()函数:代码如下:
87 void do_irq() 88 { 89 printf("key 1 down\n"); 90 static int flag=1; 91 if(flag) 92 { 93 printf("wtc_on\n"); 94 led_on(); 95 pwm_on(); 96 flag=0; 97 } 98 else if(flag == 0) 99 { 100 printf("wtc_off\n"); 101 led_off(); 102 pwm_off(); 103 flag=1; 104 } 105 EXT_INT43PEND = (1 << 2);//清中断 106 }
接下来是整个程序的代码:
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 wtc_on(); 12 void wtc_off(); 13 void pwm_on(void); 14 void pwm_off(void); 15 void led_on(void); 16 void led_on(void); 17 18 19 20 int main() 21 { 22 *(unsigned long *)0x66 = do_irq; 23 24 //发生异常时会进入异常模式跳转到0 4地址处理异常事件 25 unsigned long source_addr=data_abort_init(); 26 //异常事件处理函数 27 printf("swi_souce addr is %x\n",source_addr); 28 //将异常处理地址的值放到0x64 29 memcopy(0x60,source_addr,0x1); 30 31 enable_mmu(); 32 //内存映射将0x04映射到0x6004 33 34 //step 1: cpu cpsr 35 __asm__ __volatile__( 36 "mrs r0, cpsr\n" 37 "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开 38 "msr cpsr, r0\n" 39 ::: "r0" 40 ); 41 42 //setp1:GIC 43 ICCICR_CPU0 = 1; 44 ICCPMR_CPU0 = 0xff; 45 46 //64 47 ICDDCR = 1; 48 ICDIPR16_CPU0 = (0x0 << 0);//ICD第16个寄存器,第0位 49 ICDIPTR16_CPU0 = (0x1 << 0);//优先级,最高 50 ICDISER2_CPU0 = (1 << 0);//一共五个,第2个使能中断 51 52 //75 53 ICDIPR18_CPU0 = (0x0 << 24); 54 //ICDIPTR0_CPU0 = 1; 55 ICDIPTR18_CPU0 = (0x1 << 24); 56 //ICDISER0_CPU0 = (1 << 0); 57 ICDISER2_CPU0 = (1 << 11); 58 59 //step 3: set gpio 60 GPX3CON = (0xf << 8);//是GPXCON为外部中断功能 61 62 //step 4: extern 63 EXT_INT43CON = (2 << 8);//设置上升沿触发 64 EXT_INT43MASK = 0;//使能中断 65 66 /////////////////////////狗 67 68 //step 5: sourcevoid pwm_on(void) 69 70 71 72 printf("welcome back! \n"); 73 } 74 75 void pwm_on(void) 76 { 77 GPD0CON &= ~0xffff; 78 GPD0CON = 0x1;//配置寄存器为2 79 GPD0DAT = 0x1;//date=0xf 80 } 81 82 void pwm_off(void) 83 { 84 GPD0CON &= ~0xffff; 85 GPD0CON = 0x0; 86 // GPD0DAT &=0x0 ;//date=0xf 87 88 } 89 void led_off(void) 90 { 91 GPM4CON &= ~0xffff;//清零 92 GPM4CON = 0x0;//03位清零 93 GPM4DAT = 0x0;//date=0xf关闭置一 94 } 95 void led_on(void) 96 { 97 GPM4CON &= ~0xffff; 98 GPM4CON = 0x1;//配置寄存器3-0--3-3全为1,全为输出模式 99 GPM4DAT &= ~0xf;//打开置0-4位为0 100 } 101 102 void wtc_on() 103 { 104 //step 3: interrupt source watchdog 105 WTCON = 0 (1 << 2) (3 << 3) (1 << 5) (20 << 8); 106 WTCNT = 0x8; 107 WTDAT = 0x2; 108 } 109 110 void wtc_off() { 112 WTCON = 0; 113 } 114 115 void do_irq() 116 { 117 // pwm_on(); 118 // led_on(); 119 // delay(6); 120 // pwm_off(); 121 // led_off(); 122 123 unsigned long data = ICCIAR_CPU0; 124 unsigned long irq_id = data & 0x3ff; 125 unsigned long cpu_id = (data >> 10) & 0x7; 126 ICCEOIR_CPU0 = irq_id (cpu_id << 10); 127 printf("irq is %d, cpu is %d\n", irq_id, cpu_id); 128 if(irq_id==64)//如果按键中断 129 { 130 if(EXT_INT43PEND & (1 << 2)) 131 { 132 EXT_INT43PEND = (1 << 2);//清中断 133 printf("key 1 down\n"); 134 static int flag=1; 135 if(flag) 136 { 137 printf("wtc_on\n"); 138 wtc_on(); 139 flag=0; 140 } 141 else if(flag == 0) 142 { 143 printf("wtc_off\n"); 144 wtc_off(); 145 led_off(); 146 pwm_off(); 147 flag=1; 148 } 149 } 150 } 151 if(irq_id==75)//如果DOG中断 152 { 153 printf("dog dog dog \n"); 154 static int flag=1; 155 if(flag) 156 { 157 led_on(); 158 pwm_on(); 159 flag=0; 160 } 161 else 162 { 163 led_off(); 164 pwm_off(); 165 flag=1; 166 } 167 WTCLRINT = 100;//清狗中断 168 } 169 170 } 171 172 void memcopy(unsigned long* dest, unsigned long* source,int len) 173 { 174 int i=0;; 175 for(i=0;i> 20] = pa 2; 280 //2的目的是将0-2位置为10此时将是小页模式4K 281 } 282 283 //00-10 ==== 6070 284 for(va=0x00; va<=0x10; va+=0x100){ 285 pa = va+0x60; 286 addr[va >> 20] = pa 2; 287 } 288 289 //10-14 ==== 1014 290 for(va=0x10; va<=0x14; va+=0x100){ 291 pa = va; 292 addr[va >> 20] = pa 2; 293 } 294 295 //30-40 ==== 5060 296 for(va=0x30; va<0x40; va+=0x100){ 297 pa = va + 0x20; 298 addr[va >> 20] = pa 2; 299 } 300 } 301 302 void enable_mmu(void) 303 304 { 305 unsigned long addr = 0x70; 306 init_ttb(addr); 307 //step:初始化页表 308 309 unsigned long mmu = 1 (1 << 1) (1 << 8); 310 //将MMU的第0,1,8位置1 311 __asm__ __volatile__( 312 "mov r0, #3\n" 313 "MCR p15, 0, r0, c3, c0, 0\n"//manager 314 "MCR p15, 0, %0, c2, c0, 0\n"//addr 315 "MCR p15, 0, %1, c1, c0, 0\n"// enable mmu 316 : 317 : "r" (addr), "r" (mmu) 318 : "r0" 319 ); 320 printf("MMU is enable!\n"); 321 } 322
运行成功:
发现当按下按键是触发外部中断,LED和蜂鸣器工作,当再次按下按键的时候,停止工作!看门狗在这里的作用就是
不断的使LED和蜂鸣器闪烁和鸣叫。
到这里,ARM体系结构到一段落
上一篇:单片机脚本语言移植lua到stm32MDK
下一篇:裸奔程序之外部中断检测按键
推荐阅读最新更新时间:2024-03-16 14:53