ARM中外部中断

在整个ARM体系结构中,为了处理外部中断,依次学习了MMU,模式跳转,异常,GIC,看门狗程序,这些都是为了处理外部中断

具体如下:

处理外部中断有五个步骤:

 30      //step 1: cpu cpsr
 31       __asm__ __volatile__(
 32           "mrs r0, cpsr "
 33           "bic r0, r0, #0x80 "//设置CPSR的I位,将IRQ位打开
 34           "msr cpsr, r0 "
 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个使能中断


 47

  第二步为设置中断号

 详细看代码注释:寄存器参考手册第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 *)0x66000000 = do_irq;
 19 
 20     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   
 21     unsigned long source_addr=data_abort_init();
 22     //异常事件处理函数
 23     printf("swi_souce addr is %x
",source_addr);
 24     //将异常处理地址的值放到0x60000004
 25     memcopy(0x60000000,source_addr,0x1000);
 26 
 27     enable_mmu();
 28     //内存映射将0x00000004映射到0x6000000004    
 29 
 30      //step 1: cpu cpsr
 31       __asm__ __volatile__(
 32           "mrs r0, cpsr
"
 33           "bic r0, r0, #0x80
"//设置CPSR的I位,将IRQ位打开
 34           "msr cpsr, r0
"
 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! 
");
 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 |= 0x0000;//0---3位清零
 78         GPM4DAT |= 0x0;//date=0xf关闭置一
 79     }
 80 void led_on(void)
 81     {
 82         GPM4CON &= ~0xffff;
 83         GPM4CON |= 0x1111;//配置寄存器3-0-----3-3全为1111,全为输出模式
 84         GPM4DAT &= ~0xf;//打开置0-4位为0000
 85     }
 86 
 87 void do_irq()
 88     {
 89             printf("key 1 down
");
 90             static int flag=1;
 91             if(flag)
 92             {
 93                 printf("wtc_on
");
  94                 led_on();
 95                 pwm_on();
 96                 flag=0;
 97             }
 98             else if(flag == 0)
 99             {
100                 printf("wtc_off
");
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;;
111     for(i=0;i<len;i++)
112         dest[i]=source[i];
113 }
114 
115 unsigned long  data_abort_init()
116 {
117     unsigned long source;
118     __asm__ __volatile__(
119          "ldr %0, =voliate_start
"
120          : "=r" (source)
121      );
122     return source;
123 
124 }
125 
126 __asm__(
127 
128 "voliate_start:
"
129     //跳转目录
130     " b reset
"
131     " b undefined
"
132     " b swi
"
133     " b pre_abt
"
134     " b data_abt
"
135     " .word 0
"//占位符号,一个位占4个字节
136     " b irq
"
137     " b fiq
"
138 "
"
139 
140     //跳转要分三部:
141     //1:将PC保存到新模式下的lr中;
142     //2:将CPSR保存在SPSR中
143     //3:初始化SP
144     //前两步由硬件完成,而第三部需要手动完成
145 "reset:
"
146 
147 "undefined:
"
148      "mov sp, #0x66000000
"//初始化SP
149      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
150     //打印一句话 
151      "ldr r0, =und_string
"
152      "ldr r2, show
"
153      "blx r2
"
154     //跳回来分两部
155     //1:将CPSR保存在SPSR中
156     //2:将PC保存到新模式下的lr中;
157      "mov sp, #0x66000000
"//
158      "ldmea sp, {r0-r12, pc}^
"// 
159 
160 "swi:
"
161 
162 "pre_abt:
"
163 "data_abt:
"
164      "sub lr, lr, #4
"
165      "mov sp, #0x66000000
"//初始化SP
166      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
167     //打印一句话 
168      "ldr r0, =data_string
"
169      "ldr r2, show
"
170      "blx r2
"
171     //跳回来分两部
172     //1:将CPSR保存在SPSR中
173     //2:将PC保存到新模式下的lr中;
174      "mov sp, #0x66000000
"//
175      "ldmea sp, {r0-r12, pc}^
"// 
176 
177 "irq:
"
178     "sub lr, lr, #4
"
179      "mov sp, #0x66000000
"//初始化SP
180      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
181     //打印一句话 
182      "mov r2, #0x66000000
"
183      "ldr r1, [r2]
"
184      "blx r1
"
185 
186     "mov sp, #0x66000000
"//
187      "ldmea sp, {r0-r12, pc}^
"//
188 "fiq:
"
189     "show:
"
190      ".word 0xc3e114d8
"
191 
192     "und_string:
"
193      ".asciz "This is  UND!\n" 
"
194      "data_string:
"
195      ".asciz "This DATA_ABORT!\n" 
"
196      "irq_string:
"
197      ".asciz "This IRQ!\n" 
"
198 
199         );
200 
201 void init_ttb(unsigned long *addr)
202 {
203     unsigned long va = 0;//定义虚拟地址
204     unsigned long pa = 0;//定义物理地址
205 
206     //40000000-------80000000   ====  40000000------80000000
207     for(va=0x40000000; va<=0x80000000; va+=0x100000){
208         pa = va;
209         addr[va >> 20] = pa | 2;
210         //|2的目的是将0-2位置为10此时将是小页模式4K
211     }
212 
213     //00000000-------10000000   ====  60000000------70000000
214     for(va=0x00000000; va<=0x10000000; va+=0x100000){
215         pa = va+0x60000000;
216         addr[va >> 20] = pa | 2;
217     }
218 
219     //10000000-------14000000   ====  10000000------14000000
220     for(va=0x10000000; va<=0x14000000; va+=0x100000){
221         pa = va;
222         addr[va >> 20] = pa | 2;
223     }
224 
225     //30000000-------40000000   ====  50000000------60000000
226     for(va=0x30000000; va<0x40000000; va+=0x100000){
227         pa = va + 0x20000000;
228         addr[va >> 20] = pa | 2;
229     }
230 }
231 
232 void enable_mmu(void)
233 
234 {
235     unsigned long addr = 0x70000000;
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
"
243         "MCR p15, 0, r0, c3, c0, 0
"//manager
244         "MCR p15, 0, %0, c2, c0, 0
"//addr  
245         "MCR p15, 0, %1, c1, c0, 0
"// enable mmu
246         :
247         : "r" (addr), "r" (mmu)
248         : "r0"
249     );
250     printf("MMU is enable!
");
251 }
252 
253 
254 
                                                                                                                                                                                                                                                                             

需要注意的是:在do_irq()函数中有一个清中断的操作,否则,将会告诉中断控制器处理好了中断,以免一直触发外部中断:

87 void do_irq()
 88     {
 89             printf("key 1 down ");
 90             static int flag=1;
 91             if(flag)
 92             {
 93                 printf("wtc_on ");
 94                 led_on();
 95                 pwm_on();
 96                 flag=0;
 97             }
 98             else if(flag == 0)
 99             {
100                 printf("wtc_off ");
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
");
 90             static int flag=1;
 91             if(flag)
 92             {
 93                 printf("wtc_on
");
 94                 led_on();
 95                 pwm_on();
 96                 flag=0;
 97             }
 98             else if(flag == 0)
 99             {
100                 printf("wtc_off
");
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 *)0x66000000 = do_irq;
 23 
 24     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   
 25     unsigned long source_addr=data_abort_init();
 26     //异常事件处理函数
 27     printf("swi_souce addr is %x
",source_addr);
 28     //将异常处理地址的值放到0x60000004
 29     memcopy(0x60000000,source_addr,0x1000);
 30 
 31     enable_mmu();
 32     //内存映射将0x00000004映射到0x6000000004    
 33 
 34      //step 1: cpu cpsr
 35       __asm__ __volatile__(
 36           "mrs r0, cpsr
"
 37           "bic r0, r0, #0x80
"//设置CPSR的I位,将IRQ位打开
 38           "msr cpsr, r0
"
 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! 
");
 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 |= 0x0000;//0---3位清零
 93         GPM4DAT |= 0x0;//date=0xf关闭置一
  94     }
 95 void led_on(void)
 96     {
 97         GPM4CON &= ~0xffff;
 98         GPM4CON |= 0x1111;//配置寄存器3-0-----3-3全为1111,全为输出模式
 99         GPM4DAT &= ~0xf;//打开置0-4位为0000
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 = 0x8000;
107         WTDAT = 0x2000;
108     }
109 
110 void wtc_off()
111 {
112         WTCON = 0;
113 }
114 
115 void do_irq()
116     {
117     //   pwm_on();
118     //   led_on();
119      //    delay(6000000);
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
", 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
");
134             static int flag=1;
135             if(flag)
136             {
137                 printf("wtc_on
");
138                 wtc_on();
139                 flag=0;
140             }
141             else if(flag == 0)
142             {
143                 printf("wtc_off
");
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  
");
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<len;i++)
176         dest[i]=source[i];
177 }
178 
179 unsigned long  data_abort_init()
180 {
181     unsigned long source;
182     __asm__ __volatile__(
183          "ldr %0, =voliate_start
"
184          : "=r" (source)
185      );
186     return source;
187 
188 }
189 
190 __asm__(
191 
192 "voliate_start:
"
193     //跳转目录
194     " b reset
"
195     " b undefined
"
196     " b swi
"
197     " b pre_abt
"
198     " b data_abt
"
199     " .word 0
"//占位符号,一个位占4个字节
200     " b irq
"
201     " b fiq
"
202 "
"
203 
204     //跳转要分三部:
205     //1:将PC保存到新模式下的lr中;
206     //2:将CPSR保存在SPSR中
207     //3:初始化SP
208     //前两步由硬件完成,而第三部需要手动完成
209 "reset:
"
210 
211 "undefined:
"
212      "mov sp, #0x66000000
"//初始化SP
213      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
214     //打印一句话 
215      "ldr r0, =und_string
"
216      "ldr r2, show
"
217      "blx r2
"
218     //跳回来分两部
219     //1:将CPSR保存在SPSR中
220     //2:将PC保存到新模式下的lr中;
221      "mov sp, #0x66000000
"//
222      "ldmea sp, {r0-r12, pc}^
"// 
223 
224 "swi:
"
225 
226 "pre_abt:
"
227 "data_abt:
"
228      "sub lr, lr, #4
"
229      "mov sp, #0x66000000
"//初始化SP
230      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
231     //打印一句话 
232      "ldr r0, =data_string
"
233      "ldr r2, show
"
234      "blx r2
"
235     //跳回来分两部
236     //1:将CPSR保存在SPSR中
237     //2:将PC保存到新模式下的lr中;
238      "mov sp, #0x66000000
"//
239      "ldmea sp, {r0-r12, pc}^
"// 
240 
241 "irq:
"
242     "sub lr, lr, #4
"
243      "mov sp, #0x66000000
"//初始化SP
244      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
245     //打印一句话 
246      "mov r2, #0x66000000
"
247      "ldr r1, [r2]
"
248      "blx r1
"
249 
250    //  "ldr r0, =irq_string
"
251    //  "ldr r2, show
"
252    //  "blx r2
"
253     //跳回来分两部
254     //1:将CPSR保存在SPSR中
255     //2:将PC保存到新模式下的lr中;
256      "mov sp, #0x66000000
"//
257      "ldmea sp, {r0-r12, pc}^
"//
258 "fiq:
"
259     "show:
"
260      ".word 0xc3e114d8
"
261 
262     "und_string:
"
263      ".asciz "This is  UND!\n" 
"
264      "data_string:
"
265      ".asciz "This DATA_ABORT!\n" 
"
266      "irq_string:
"
267      ".asciz "This IRQ!\n" 
"
268 
269         );
270 
271 void init_ttb(unsigned long *addr)
272 {
273     unsigned long va = 0;//定义虚拟地址
274     unsigned long pa = 0;//定义物理地址
275 
276     //40000000-------80000000   ====  40000000------80000000
277     for(va=0x40000000; va<=0x80000000; va+=0x100000){
278         pa = va;
279         addr[va >> 20] = pa | 2;
280         //|2的目的是将0-2位置为10此时将是小页模式4K
281     }
282 
283     //00000000-------10000000   ====  60000000------70000000
284     for(va=0x00000000; va<=0x10000000; va+=0x100000){
285         pa = va+0x60000000;
286         addr[va >> 20] = pa | 2;
287     }
288 
289     //10000000-------14000000   ====  10000000------14000000
290     for(va=0x10000000; va<=0x14000000; va+=0x100000){
291         pa = va;
292         addr[va >> 20] = pa | 2;
293     }
294 
295     //30000000-------40000000   ====  50000000------60000000
296     for(va=0x30000000; va<0x40000000; va+=0x100000){
297         pa = va + 0x20000000;
298         addr[va >> 20] = pa | 2;
299     }
300 }
301 
302 void enable_mmu(void)
303 
304 {
305     unsigned long addr = 0x70000000;
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
"
313         "MCR p15, 0, r0, c3, c0, 0
"//manager
314         "MCR p15, 0, %0, c2, c0, 0
"//addr  
315         "MCR p15, 0, %1, c1, c0, 0
"// enable mmu
316         :
317         : "r" (addr), "r" (mmu)
318         : "r0"
319     );
320     printf("MMU is enable!
");
321 }
322 
                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                                                                

运行成功:

发现当按下按键是触发外部中断,LED和蜂鸣器工作,当再次按下按键的时候,停止工作!看门狗在这里的作用就是

不断的使LED和蜂鸣器闪烁和鸣叫。

到这里,ARM体系结构到一段落

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