Exynos4412裸机开发——中断处理

       以KEY2控制LED3亮灭为例:

一、轮询方式

【0】检测按键k2,按键k2按下一次,灯LED2闪一次。

【1】查看原理图,连接引脚和控制逻辑
(1)按键k2 连接在GPX1_1引脚
(2)控制逻辑
       k2 按下  ---- K2闭合 ---- GPX1_1 低电压
       k2 常态  ---- K2打开 ---- GPX1_1 高电压

【2】查看相应的芯片手册

    【2-1】循环检测GPX1_1引脚输入的电平,为低电压时,按键按下

        (1)配置GPX1_1引脚功能为输入,设置内部上拉下拉禁止。
                  GPX1.CON = GPX1.CON &(~(0xf<<4)) ;

                  GPX1.PUD = GPX1.PUD & ~(0x3 << 2);
  (2)循环检测:

[cpp]  view plain  copy
  1. while(1)  
  2. {  
  3.     if(!(GPX1.DAT & (0x1<<1)))  // 返回为真,按键按下  
  4.     {      
  5.         msdelay(10);  
  6.         if(!(GPX1.DAT & (0x1<<1))) //二次检测,去抖  
  7.         {  
  8.             GPX2.DAT |= 0x1 << 7;  //Turn on LED2  
  9.             mydelay_ms(500);  
  10.             GPX2.DAT &= ~(0x1<<7);  //Turn off LED2  
  11.             mydelay_ms(500);  
  12.         
  13.             while(!(GPX1.DAT & (0x1<<1)));  
  14.         }  
  15.     }  
  16. }  

这种轮询方式始终占着CPU,不利于操作。

 

二、中断方式

         将K2按下时,GPX1_1引脚获得的电平,作为异常事件。使能异常处理,k2每按下一次,响应一次异常处理。SPI 传递流程如下示:

注:

      Exynos4412中断控制器包括160个中断控制源,这些中断源来自软中断(SGI),私有外部中断(PPI),公共外部中断(SPI)。

      Exynos4412采用GIC中断控制器,主要是因为Contex-A9 是多核处理器,GIC(Generic Interrupt Controller)通用中断控制器用来选择使用哪个CPU接口,具体主要有两个功能:

1)分配器:设置一个开关,是否接收外部中断源;为该中断源选择CPU接口;

2)CPU接口:设置一个开发,是否接受该中断源请求;

 

具体实现如下:

1、外设一级 ---设置 GPIO控制器

1-- 将GPX1_1引脚的上拉和下拉禁止

        GPX1PUD[3:2]= 0b00;

2 -- 将GPX1_1引脚功能设置为中断功能 WAKEUP_INT1[1] --- EXT_INT41[1]

        GPX1CON[7:4] = 0xf

3 -- EXT_INT41CON  配置触发电平

       当前配置成下降沿触发:

       EXT_INT41CON[6:4] = 0x2

4 -- EXT_INT41_FLTCON0 配置中断引脚滤波

       默认就是打开的,不需要配置

5 -- EXT_INT41_MASK 中断使能寄存器

      使能INT41[1]

      EXT_INT41_MASK[1] = 0b0

6 -- EXT_INT41_PEND 中断状态寄存器
       当GPX1_1引脚接收到中断信号,中断发生,中断状态寄存器EXT_INT41_PEND 相应位会自动置1
        注意:中断处理完成的时候,需要清除相应状态位。置1清0.
        EXT_INT41_PEND[1] =0b1 

 

2、中断控制器

1-- 找到外设中断名称和GIC中断控制器对应的名称

    查看芯片手册(本例:Exynos_4412 -- 9.2表)
       WAKEUP_INT1[1] --- EXT_INT41[1] --- INT[9] --- SPI[25]/ID[57]

      其对应INT[9],中断ID为57,这是非常重要的,在后面的寄存器设置中起很大作用;

 

下面是外设与中断控制器处理具体流程:

 

2 -- GIC使能

       ICDDCR =1;

       使能分配器。

3 -- 使能相应中断到分配器

      ICDISER.ICDISER1 |= (0x1 << 25);    //57/32 =1...25 取整数(那个寄存器) 和余数(哪位)

      ICDISER用于使能相应中断到分配器,一个bit控制一个中断源,一个ICDISER可以控制32个中断源,这里INT[9] 对应的中断ID为57,所以在ICDSER1中进行设置,57/32 =1余25,所以这里在ICDISER1第25位置一。

 

4 -- 选择CPU接口

      设置SPI[25]/ID[57]由那个cpu处理,当前设置为cpu0的irq中断

      ICDIPTR.ICDIPTR14 |= 0x01<<8; //SPI25  interrupts are sent to processor 0   //57/4 = 14..1 14号寄存器的[15:8]

      ICDIPTR寄存器每8个bit 控制一个中断源

 

5 -- 全局使能cpu0中断处理

       CPU0.ICCICR |= 0x1;

       使能中断到CPU。

 

6 -- 优先级屏蔽寄存器,设置cpu0能处理所有的中断。

      CPU0.ICCPMR = 0xFF;

                          

3、ARM内核(cpu0)

       前面两步设置好,就可以等待中断的发生了,当中断发生时,ARM内核的处理过程如下:

 

 1-- 四大步三小步 --- 硬件

    

      (1)拷贝 CPSR 到 SPSR_<mode>
  (2)设置适当的 CPSR 位:                                
    (2-1)--改变处理器状态进入 ARM 态
       (2-2)--改变处理器模式进入相应的异常模式
       (2-3)--设置中断禁止位禁止相应中断 (如果需要)
  (3)保存返回地址到 LR_<mode>
  (4)设置 PC 为相应的异常向量
          

2 -- 中断服务程序 --- start.S 汇编

[cpp]  view plain  copy
  1. .text  
  2. .global _start  
  3. _start:  
  4.         b       reset  
  5.         ldr     pc,_undefined_instruction  
  6.         ldr     pc,_software_interrupt  
  7.         ldr     pc,_prefetch_abort  
  8.         ldr     pc,_data_abort  
  9.         ldr     pc,_not_used  
  10.         ldr     pc,_irq  
  11.         ldr     pc,_fiq  
  12.   
  13. _undefined_instruction: .word  _undefined_instruction  
  14. _software_interrupt:    .word  _software_interrupt  
  15. _prefetch_abort:        .word  _prefetch_abort  
  16. _data_abort:            .word  _data_abort  
  17. _not_used:              .word  _not_used  
  18. _irq:                   .word  irq_handler  
  19. _fiq:                   .word  _fiq  
  20.   
  21.   
  22. reset:  
  23.   
  24.     ldr r0,=0x40008000  
  25.     mcr p15,0,r0,c12,c0,0       @ Vector Base Address Register  
  26.   
  27.   
  28. init_stack:  
  29.         ldr     r0,stacktop         /*get stack top pointer*/  
  30.   
  31.     /********svc mode stack********/  
  32.         mov     sp,r0  
  33.         sub     r0,#128*4          /*512 byte  for irq mode of stack*/  
  34.     /****irq mode stack**/  
  35.         msr     cpsr,#0xd2  
  36.         mov     sp,r0  
  37.         sub     r0,#128*4          /*512 byte  for irq mode of stack*/  
  38.     /***fiq mode stack***/  
  39.         msr     cpsr,#0xd1  
  40.         mov     sp,r0  
  41.         sub     r0,#0  
  42.     /***abort mode stack***/  
  43.         msr     cpsr,#0xd7  
  44.         mov     sp,r0  
  45.         sub     r0,#0  
  46.     /***undefine mode stack***/  
  47.         msr     cpsr,#0xdb  
  48.         mov     sp,r0  
  49.         sub     r0,#0  
  50.    /*** sys mode and usr mode stack ***/  
  51.         msr     cpsr,#0x10  
  52.         mov     sp,r0             /*1024 byte  for user mode of stack*/  
  53.   
  54.         b       main  
  55.   
  56.     .align  4  
  57.   
  58.     /****  swi_interrupt handler  ****/  
  59.   
  60.   
  61.     /****  irq_handler  ****/  
  62. irq_handler:  
  63.   
  64.     sub  lr,lr,#4  
  65.     stmfd sp!,{r0-r12,lr}  
  66.     .weak do_irq  
  67.     bl  do_irq  
  68.     ldmfd sp!,{r0-r12,pc}^  
  69.   
  70. stacktop:    .word      stack+4*512  
  71. .data  
  72.   
  73. stack:   .space  4*512  

 

3--中断处理程序 --- do_irq函数 c语言(函数原型void name(void))

(1) 读取正在处理的中断ID寄存器(ICCIAR)

          irq_num = (CPU0.ICCIAR & 0x1FF);

(2)根据irq_num,分支处理中断  

[cpp]  view plain  copy
  1. switch(irq_num)  
  2. {  
  3.     .  
  4.     case 57:  
  5.         break;  
  6.     ....  
  7.   
  8. }  


 (3)清除中断状态位

        (3-1)i.外设级,EXT_INT41_PEND |= 0x1 << 1;
        (3-2)ii.GIC级,ICDICPR.ICDICPR1 |= 0x1 << 25;
        (3-3)iii.CPU0级 CPU0.ICCEOIR = (CPU0.ICCEOIR & ~(0x1FF)) | irq_num;

 

下面是C 程序:

[cpp]  view plain  copy
  1. #include "exynos_4412.h"  
  2. #include "led.h"  
  3.   
  4. void  delay_ms(unsigned int num)  
  5. {  
  6.     int i,j;  
  7.     for(i=num; i>0;i--)  
  8.     for(j=1000;j>0;j--)  
  9.         ;  
  10. }  
  11. void do_irq(void)  
  12. {  
  13.     static int a = 1;  
  14.     int irq_num;  
  15.     irq_num = CPU0.ICCIAR&0x3ff;  //获取中断号  
  16.     switch(irq_num)  
  17.     {  
  18.     case 57:  
  19.         printf("in the irq_handler\n");  
  20.             if(a)  
  21.                 led_on(1);  
  22.             else  
  23.                 led_off(1);  
  24.             a = !a;  
  25.             EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); //清GPIO中断标志位  
  26.             ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); //清GIC中断标志位  
  27.         break;  
  28.     }  
  29.     CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num; //清cpu中断标志位  
  30. }  
  31. /* 
  32.  *  裸机代码,不同于LINUX 应用层, 一定加循环控制 
  33.  */  
  34. int main (void)  
  35. {  
  36.     GPX1.CON =GPX1.CON & (~(0xf << 4)) |(0xf << 4); //配置引脚功能为外部中断  
  37.     GPX1.PUD = GPX1.PUD & (~(0x3 << 2));  //关闭上下拉电阻  
  38.     EXT_INT41_CON = EXT_INT41_CON &(~(0xf << 4))|(0x2 << 4); //外部中断触发方式  
  39.     EXT_INT41_MASK = EXT_INT41_MASK & (~(0x1 << 1));  //使能中断  
  40.     ICDDCR = 1;  //使能分配器  
  41.     ICDISER.ICDISER1 = ICDISER.ICDISER1 | (0x1 << 25); //使能相应中断到分配器  
  42.     ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xff << 8))|(0x1 << 8); //选择CPU接口  
  43.     CPU0.ICCPMR = 255; //中断屏蔽优先级  
  44.     CPU0.ICCICR = 1;   //使能中断到CPU  
  45.     led_init();  
  46.     while(1)  
  47.     {  
  48.   
  49.     }  
  50.    return 0;  
  51. }  


 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值