bootloader启动代码init.s解析----IRQ中断处理函数
init.s源代码如下:
;///////////////////////////////////////////// ;option.inc _ISR_STARTADDRESS EQU 0x33ffff00
;2440addr.inc
INTOFFSET EQU 0x4a000014 ;Interruot request source offset ;///////////////////////////////////////////// ;init.s ;/////////////////////宏 MACRO $HandlerLabel HANDLER $HandleLabel $HandlerLabel sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work register to stack(lr does t push because it return to original address) ldr r0,=$HandleLabel;load the address of HandleXXX to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) MEND ;////////////////////////;入口处定义中断跳转 ResetEntry b ResetHandler b HandlerUndef ;handler for Undefined mode b HandlerSWI ;handler for SWI interrupt b HandlerPabort ;handler for PAbort b HandlerDabort ;handler for DAbort b . ;reserved b HandlerIRQ ;handler for IRQ interrupt b HandlerFIQ ;handler for FIQ interrupt HandlerFIQ HANDLER HandleFIQ HandlerIRQ HANDLER HandleIRQ HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabort IsrIRQ ;定义IsrIRQ函数 sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ;r8=r8+(r9*4) ldr r8,[r8] str r8,[sp,#8] ldmfd sp!,{r8-r9,pc} ResetHandler ;....此处省略,其他操作如看门狗、sram初始化、堆栈初始化等 ....
;Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0] ;这样,在地址值为HandleIRQ(0x33FF_FF1C)处,装着IsrIRQ函数指针。 ;....此处省略,拷贝程序、跳转main等.... ;///////////////////////////////////////////////////////////////;定义中断地址 ^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00 HandleReset # 4 ;0x33FF_FF04 HandleUndef # 4 ;0x33FF_FF08 HandleSWI # 4 ;0x33FF_FF0c HandlePabort # 4 ;0x33FF_FF10 HandleDabort # 4 ;0x33FF_FF14 HandleReserved # 4 ;0x33FF_FF18 HandleIRQ # 4 ;0x33FF_FF1C HandleEINT0 # 4 ;@0x33FF_FF20
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleCAM # 4 ; Added for 2440.
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
;@0x33FF_FF60
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleNFCON # 4 ; Added for 2440.
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
HandleRTC # 4
HandleADC # 4
把异常处理的宏展开,以HandlerIRQ HANDLER HandleIRQ为例:
HandlerIRQ HANDLER HandleIRQ 展开: HandlerIRQ sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work register to stack(lr does t push because it return to original address) ldr r0,=HandleIRQ ;load the address of HandleIRQ to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleIRQ ;这里的contents是参照下面Setup IRQ handler ,为IsrIRQ函数指针 str r0,[sp,#4] ;store the contents(ISR) of HandleIRQ to stack ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) MEND
中断发生时,b HandlerIRQ
HandlerIRQ 展开后代码如上所示,流程如下图,最终跳转到了中断处理函数IsrIRQ【*HandleIRQ = IsrIRQ】:
在IsrIRQ里面,跳转到具体的中断处理函数。
IsrIRQ sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ldr r8,[r8] ;//r8 = HandleEINT0 + INTOFFSET寄存器的值*4 ;这里对应的是C代码中定义的中断响应函数的地址。怎么对应上的?见如下的代码: str r8,[sp,#8] ldmfd sp!,{r8-r9,pc}
C代码中: 关联中断处理函数和启动代码中的中断地址。 //option.h #define _ISR_STARTADDRESS 0x33ffff00
//addr.h #define pISR_UART1 (*(unsigned *)(_ISR_STARTADDRESS+0x7c))
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20)) ;0x33FF_FF20
//IsrBind() // isr_init.c
pISR_UART1=(unsigned int)ProcomUart1IsrFunction; 在逻辑代码中,地址值是绝对的,因此C中的_ISR_STARTADDRESS正是启动代码中的_ISR_STARTADDRESS。 那pISR_UART1表示的就是*(HandleUART1)。pISR_EINT0就是*(HandleEINT0).
这里可以得出:我们的C代码中可以在pISR_EINT0里面分发外部中断,也可以直接绑定到具体中断源。这无非是一个中断地址表和中断处理函数的对应。
IsrIRQ跳转图解:
下面总结中断触发如何引发调用中断函数:
//先后关系:
硬件中断发生
--->
中断相关寄存器的值产生相应变化(INT_OFFSET反映了具体的外部中断源)
--->
b HandlerIRQ()
--->
HandleIRQ()
--->
IsrIRQ()
--->//如上图IsrIRQ的解析所示,根据INT_OFFSET和事先制定的地址对照表,跳转到C中初始化时绑定的中断函数
one of irq_funcs
扩展阅读:
1. 2440之中断管理 http://www.cnblogs.com/hnrainll/archive/2011/07/01/2095464.html