• 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体系结构到一段落

  • 相关阅读:
    MySQL-数据表操作
    MySQL基础命令
    Navicat 15激活
    禅道-启动失败问题整理
    python-开头的注释作用及区别
    SpringBoot、SpringCloud版本中GA/PRE/SNAPSHOT的详解
    mybatis的一些重要配置
    简历对应的知识点
    idea的破解
    SFTP和FTP的区别
  • 原文地址:https://www.cnblogs.com/hongzhunzhun/p/4515300.html
Copyright © 2020-2023  润新知