现在的位置: 首页 > 综合 > 正文

ARM对中断IRQ的处理

2013年01月02日 ⁄ 综合 ⁄ 共 3939字 ⁄ 字号 评论关闭
  •  Startup中断向量表

     ;*******************************************************************************
     ; Exception vectors
    ;*******************************************************************************
    LDR PC, Reset_Addr     ;  地址为0x8000 0000
    LDR PC, Undefined_Addr
    LDR PC, SWI_Addr
    LDR PC, Prefetch_Addr
    LDR PC, Abort_Addr
    NOP ; Reserved vector
    LDR PC, IRQ_Addr
    LDR PC, FIQ_Addr
   ; *******************************************************************************
   ; Exception handlers address table
   ;*******************************************************************************
   Reset_Addr DCD __program_start ;地址为0x8000 0020
   Undefined_Addr DCD UndefinedHandler
   SWI_Addr DCD SWIHandler
   Prefetch_Addr DCD PrefetchAbortHandler
   Abort_Addr DCD DataAbortHandler
   DCD 0 ; Reserved vector
   IRQ_Addr DCD IRQHandler
   FIQ_Addr DCD FIQHandler
   ;*******************************************************************************
   ; Peripherals IRQ handlers address table
   ;*******************************************************************************
    PRCCUCMU_Addr DCD PRCCUCMUIRQHandler ;地址为0x8000 0040

         对于嵌入式系统来说,一般将上面产生的代码放在flash中,地址0x8000 0000(该sector同时remap到0x0000 0000)。将__program_start,UndefinedHandler等地址放到指令缓冲池中。从而可以实现全局范围内跳转。根据ARM指令长度可知,上述__program_start的地址存放的物理地址是0x8000 0020,根据ARM流水线的情况,LDR PC, Reset_Addr产生汇编语言指令为LDR PC, [PC, #24]。

IRQ中断发生时,程序跳转到IRQHandler处。

  • IRQHandler

IRQHandler
      SUB lr,lr,#4 ; Update the link register
      SaveContext r0,r12 ; Save the workspace plus the current
                                        ; return address lr_ irq and spsr_irq. 
      LDR lr, =ReturnAddress; Read the return address.
      LDR r0, =EIC_base_addr 
      LDR r1, =IVR_off_addr 
      ADD pc,r0,r1 ; Branch to the IRQ handler.
ReturnAddress
     ; Clear pending bit in EIC (using the proper IPRx)
     LDR r0, =EIC_base_addr
     LDR r2, [r0, #CICR_off_addr] ; Get the IRQ channel number
    CMP r2,#31
    SUBHI r2, r2, #32 
    MOV r3,#1
    MOV r3,r3,LSL r2
    STRHI r3,[r0, #IPR1_off_addr] ; Clear the corresponding IPR bit.
    STRLS r3,[r0, #IPR0_off_addr] ; Clear the corresponding IPR bit.

    RestoreContext r0,r12 ; Restore the context and return to the...
    ; ...program execution.
    其中,EIC_base_addr0xFFFF FC00IVR的地址是0xFFFF FC18,通过执行该寄存器中的指令可进入到相应的中断服务程序,该寄存器可在通过install中断向量服务程序时进行设置。例如该IVR寄存器的值为0xE59FF468,则表示LDR PC, [PC, #1128]。其实就是跳转到指令缓冲区中定义Timer2中断服务程序。

  • Interrupt Vector Register和Source Interrupt Registers的设置
  •   extern u32 PRCCUCMU_Addr;
         u8 Counter=0;
         u32 Offset = (u32)&PRCCUCMU_Addr;         //PRCCUCMU_Addr地址为0x8000 0040
         u32 Tmp=0;

         /* IVR = high half of load PC instruction (LDR PC,) */
         EIC->IVR = 0xE59F0000;                                  //0xE59F0000,根据Instruction format表示一条无条 
                                                                               //件执行的语句,该指令向目的寄存器PC传递值,
                                                                               //指令中的F,表示r15即PC
        /* Read the offset of the interrupt vectors table address */
        Offset = (Offset+0x3E0)<<16;                      //偏移地址问什么要加上0x3E0? 是因为
                                                                              //0x8000 0040 + 0x3E0 << 16 = 0x0420 0000,
                                                                              //中断发生后,SIR的高16bits会传递到IVR的低
                                                                              //16bit作为偏移地址,而IVR地址为0xFFFF FC18
                                                                              //0xFFFF FC18 + 0x420 + 0x8(流水线影响)=
                                                                              //0x1 0000 0040,由于ARM为32bits,故即为
                                                                              //0x40(该地址同时映射到0x8000 0040处)
     

         /* Initialize SIRn registers with the equivalent low half of load PC instruction */
        for(Counter=64; Counter!=0; Counter--)
       {
             EIC->SIRn[64-Counter] = Offset|0xF0000000;         //为什么0xF000 0000,是因为LDR PC, [PC, #0ffset],
                                                                                               //源寄存器和目的寄存器都是PC

            Offset += 0x00000004 << 16;
        }

      上面的程序片断设置IVR和SIRn等。这样当IRQ中断发生时,PC首先跳转到0xFFFF FC18处,即执行IVR寄存器中的指令LDR PC, [PC, #offset],从指令缓冲池中取出中断服务程序的地址给PC,从而跳转到中断服务程序。

  

抱歉!评论已关闭.