博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bootloader启动代码init.s解析----IRQ中断处理函数
阅读量:6222 次
发布时间:2019-06-21

本文共 4777 字,大约阅读时间需要 15 分钟。

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_FF00HandleReset     #   4        ;0x33FF_FF04HandleUndef     #   4        ;0x33FF_FF08HandleSWI       #   4        ;0x33FF_FF0cHandlePabort    #   4        ;0x33FF_FF10HandleDabort    #   4        ;0x33FF_FF14HandleReserved  #   4        ;0x33FF_FF18HandleIRQ       #   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.  http://www.cnblogs.com/hnrainll/archive/2011/07/01/2095464.html

你可能感兴趣的文章
Ubuntu安装PyCharm
查看>>
如何将CTB词性标签映射为universalPOs标签
查看>>
BZOJ5299:[CQOI2018]解锁屏幕(状压DP)
查看>>
Mac OSX 快捷键&命令行总览
查看>>
c++面试题之内存分配
查看>>
水果忍者(切西瓜)
查看>>
集合问题
查看>>
HTML
查看>>
渗透测试辅助工具--在线版
查看>>
Python(Handwriting)
查看>>
09-C语言选择结构(二)
查看>>
虚拟机类加载机制
查看>>
C++0X 学习之 auto
查看>>
火焰图&perf命令
查看>>
可乐鸡翅
查看>>
Spring MVC【入门】就这一篇!
查看>>
windows7 professional.iso
查看>>
postgresql存储过程
查看>>
vue.js的安装部署+cnpm install 安装过程卡住不动----亲测可用
查看>>
如何使用win7自带的备份还原以及创建系统镜像------傻瓜式教程
查看>>