• bootloader启动代码init.s解析----IRQ中断处理函数


    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

  • 相关阅读:
    在c++代码中执行bat文件 【转】
    华为交换机限速配置命令2016
    zabbix报错listener failed: zbx_tcp_listen() fatal error: unable to serve on any address
    shell脚本中执行mysql 语句,去除warning using a password on the command line interface can be insecure信息
    zabbix_get :command not found 解决办法
    CentOS7 升级到7.4
    jumpserver v0.5.0 创建用户和管理机器
    zabbix触发的多条件判断表达式
    nginx 配置一个文件下载服务
    ECS 实例网络带宽
  • 原文地址:https://www.cnblogs.com/mylinux/p/4140691.html
Copyright © 2020-2023  润新知