您的位置:首页 > 其它

ARM:ARM中断异常的处理流程

2017-02-19 22:00 239 查看
裸板开发中,使用的就是现在的框架:
………………………………………………………………
    main (void) {
        // 一系列的初始化
        while (1) {
            // 周期性的事物
        }
    }
             ↓+↓
          异常处理  (异步事件的处理)
………………………………………………………………

1、异常如何触发
     用按键触发异常,触发IRQ / FIQ类型的异常。

 1.1 电路原理图 // x6818bv2【底板】.pdf
    当SW6对应的按键 - 断开,导线GPIOA28 - 高电平。
    当SW6对应的按键 - 闭合,导线GPIOA28 - 低电平。
    导线GPIOA28 → 连接到了 → CPU的GPIOA28的管脚。

1.2 对GPIOA28管脚进行配置 - (市长)
    配置后GPIOA28管脚上的变化才会被视为IRQ / FIQ异常
    异常上报给ARM core
    GPIOA28'管脚上出现一个下降沿时触发中断'信号
--->P66. // 确认I/O输出
    GPIOA28 - I/O: Function0
---> P759. // 配置:输出功能 function0
    GPIOA_ALTFN1 - 0xc001a024 - [25:24] 00=ALT Function0
---> P745. // 配置:输入模式 mode
    GPIOA_OUTENB - 0xc001a004 - [ 28 ] 0=Input Mode
---> P752. // 配置:检测模式 (1+2=3bit)
    GPIOA_DETMODE1 - 0xc001a00c - [25:24] 2-bit 10=Falling Edge
    GPIOA_DETMODEEX - 0xc001a028 - [ 28 ] 1-bit 0=Falling Edge
        010 : 检测下降沿,检测到下降沿信号产生中断异常
---> P770. // 配置:检测使能
    GPIOA_DETENB - 0xc001a03c - [ 28 ] 1=Enable
---> P756. // 配置:中断源级使能
    GPIOA_INTENB - 0xc001a010 - [ 28 ] 1/0=Enable/Disable
---> P756. // 配置:检测状态显示
    GPIOA_DET - 0xc001a014 - [ 28 ] read: 0/1=未/检测到配置的信号
                                                     write: 1=清除对应的检测bit位
【对应的代码】
    key_irq.c
        void key_irq_init (void) {...}
        该函数在main.c中被调用,效果是当按键按下时产生一个中断信号
/** 代码演示  - key_irq.c **/
void do_gpioa_irq(void) {
uart_puts("\n\r do_gpioa_irq \n\r");
GPIOA_DET |= (1<<28);
}
void key_irq_init(void) {
GPIOA_INTENB &= ~(1<<28);  // 先做中断源级屏蔽
//GPIO 配置
//  1、GPIO配置为输入
//  2、禁止内部上、下拉电阻
//  3、GPIO检测使能
//  4、GPIO检测下降沿事件
//  5、GPIO中断使能
//  FUNC 0
//  输入口,禁止内部上下拉电阻
GPIOA_ALTFN1 &= ~(3<<(24));
GPIOA_OUTEN &= ~(1<<28);
//清除检测标志位
GPIOA_DET |= (1<<28);
//检测下降沿事件,使能检测
GPIOA_DETMODE1 = (GPIOA_DETMODE1 & ~(3<<24)) | (2<<24);
GPIOA_DETMODEEX &=  ~(1<<28);
GPIOA_DETENB |= (1<<28);
GPIOA_INTENB |= (1<<28); // 最后中断源级使能
}
/** ------------------------------------------------------ **/

1.3 中断控制器 GIC - (省长)
【特点】
     1)中断源可以配置为group0或者group1;
     2)group0中的中断可以配置为IRQ/FIQ的形式向目标处理器报告;
     3)grout1中的中断只能以IRQ的形式向目标处理器报告;
【支持4种类型的中断】
     SGI * 16 :软件产生的中断信号,cpu和cpu之间的通信。
     PPI * 6 :私有外围设备中断
     PPI * 1 :私有内部设备中断
     SPI * 128 :'共享的外部设备中断(按键就属于SPI)
【中断状态】
    inactive:非中断未决和中断进行。
    pending:中断未决。中断已产生,等待cpu处理阶段。
    active:中断进行。中断已产生,并正在执行相应的中断服务过程中。
【中断被处理的模式】
    1-N model    /    N-N model
【中断优先级】了解
【中断编号】interrupt IDs
    ID0~ID15:SGI
    ID16~ID31:PPI
    ID32~ID1019:SPI   // 按键可用的编号在此范围内
【中断源】---> P472.
    GPIOA中断对应的interrupt ID是 32 + 53 == 85
【关于特殊功能寄存器的设置,分两部分】
    distributor<分配器> + CPU interface<接口> = '中断控制器(GIC)'
    1)以GICD_xxxx开头的寄存器,对distributor配置;
    2)以GICC_xxxx开头的寄存器,对CPU interface配置。
" GICD_CTRL    // 归为group的中断信号是否可向interface
    GICD_CTRL - 0xc0009000 - [ 0 ] 0=屏蔽,1=使能
    
" GICD_IGROUPR    // 决定中断归为group0还是group1
    GICD_IGROUPR2 - 0xc0009088 - [ 21 ] 0=group0

" GICD_ITARGETSR21    //配置中断产生后分配给那个核(cpu0,cou1...)
           GICD_ITARGETSR21
          配置中断产生后分发给哪个核(cpu0 cpu1 ...cpu7)
          [15:8] 00000001 ID=85的中断发送到CPU0
       GICD_IPRORITYR21
          [15:8] 0x0a ID=85的中断优先级为10
       GICD_ICPENDERR2
          READ:
             1, 中断产生了未得到处理 PENDING (未决/挂起)
          WRITE,
             1  导致对应的bit 清0
          GPIOA ID = 85 
            [21] 向其中写入1,将其清0
       GICD_ISENABLER2
            [21] 0/1 屏蔽/使能 ID=85的中断信号     
      GICC_CTRL
          [0], 0/1 禁止/使能上报group0组的中断信号给CPUn
          [1], 0/1 禁止/使能上报group1组的中断信号给CPUn
          [3], 0/1 group0的中断按照IRQ/FIQ方式上报
      GICC_PMR
               中断优先级阈值设置
               优先级高于阈值的中断信号才有可能上报给CPU
          [7:0]       
    
【对应的代码】interrupt.c
      int interrupt_init (void){ }
      该函数在main.c

1.4 ARM core设置
       CPSR 
           [I] 0,响应上报的IRQ信号
               1,屏蔽上报的IRQ信号
               
      start.s
          enable_interrupts
      该函数在main.c中被调用   

 

2、异常的处理流程
   增加start.s
   
   而且调整shell.lds
   
   IRQ异常产生,硬件会自动做4件事
      1)备份CPSR 到spsr_<irq>
      2) 修改CPSR
         [4:0] 10010
         [5]  T=0
         [6]  F=1
         [7]  I=1
      3) 保存返回地址到LR_<irq>
         LR_<irq> = PC -4 
      4) 给PC寄存器赋值
         PC = vector_base + 0x18
            = 0x48000000 + 0x18
   start.s
      1)异常向量表
        b reset
        ldr ...
        ldr ...
      2)reset:
        重新设置异常向量表首地址
        栈空间设置
        bl main ( ) {
               中断源 中断控制 arm初始化 //按键就出异常并且异常可以传递ARM CORE
               
               while(1) {
               }
           }
   当有人按下key1键 ,IRQ异常报告给ARM CORE
   ARM CORE
      1)备份cpsr
      2)修改CPSR
      3)保存返回地址到LR
      4)PC = 0X48000018
   软件代码执行
       ldr   pc, _irq
       irq:
         
 保护现场  stmfd sp!, {r0-r12, lr}
           执行按键处理动作 bl do_irq
           恢复现场 ldmfd sp!, {r0-r12, r15}^
                       r15= lr
                       ^: cpsr = spsr_<irq>
       do_irq()
       {
          /*确认哪个触发的IRQ*/
          GPIOA28 interrupt id = 85
          判断是否为GPIOA28触发的中断?
          {
              do_gpioa_irq()
              {
                 /*重要的事:清除中断源的中断标志位*/
              }
              清除gpioa28在中断控制器中的pending位
          }
       }

练习:
    梳理按键异常是如何产生的?流程
    异常的软硬件响应过程?
    能不能向其中再增加一个按键?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  arm