• 2440 中断过程分析 (MDK 自带启动代码实现中断)


       最近一直想在MDK下利用自带启动代码实现中断,所以就硬着头皮看了看 ADS下的初始化代码 .现在我来分析一下ADS下的IRQ中断过程,这一部分

    主要是参考百度文库,当2440发生中断时就会自动跳到这里自动执行:

    ResetEntry
        ;1)The code, which converts to Big-endian, should be in little endian code.
        ;2)The following little endian code will be compiled in Big-Endian mode.
        ;  The code byte order should be changed as the memory bus width.
        ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
        ASSERT    :DEF:ENDIAN_CHANGE
        [ ENDIAN_CHANGE
            ASSERT  :DEF:ENTRY_BUS_WIDTH
            [ ENTRY_BUS_WIDTH=32
                b    ChangeBigEndian        ;DCD 0xea000007
            ]
    
            [ ENTRY_BUS_WIDTH=16
                andeq    r14,r7,r0,lsl #20   ;DCD 0x0007ea00
            ]
    
            [ ENTRY_BUS_WIDTH=8
                streq    r0,[r0,-r10,ror #1] ;DCD 0x070000ea
            ]
            |
            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

    如果是IRQ中断,则会跳到HandlerIRQ  这个标识符  .我们找到了HandlerIRQHANDLER HandleIRQ  这里是 一个宏定义 ,我们找到宏定义

        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 not 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

    这里把  HandlerLabel  换成  HandlerIRQ及为展开过程 . 这里的过程是保存现现场,然后跳转到真正的处理函数 .真正的处理函数是放在HandlerIRQ中的(替换之后)

    ,我们又找到  

        AREA RamData, DATA, READWRITE
    
        ^   _ISR_STARTADDRESS        ; _ISR_STARTADDRESS=0x33FF_FF00
    HandleReset     #   4
    HandleUndef     #   4
    HandleSWI        #   4
    HandlePabort    #   4
    HandleDabort    #   4
    HandleReserved  #   4
    HandleIRQ        #   4
    HandleFIQ        #   4
    
    ;Do not use the label 'IntVectorTable',
    ;The value of IntVectorTable is different with the address you think it may be.
    ;IntVectorTable
    ;@0x33FF_FF20
    HandleEINT0        #   4
    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
    ;@0x33FF_FFA0
        END

    这段代码的意思是 从_ISR_STARTADDRESS 开始预留一个变量,每个变量一个标号,预留空间为4字节 .也就是函数指针 .

    现在想想  HandleIRQ   这个指针对应是值是什么??  下面进行指针的安装  .我们找到安装句柄的语句:

         ; 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]

    这几句很容易理解,  就是IsrIRQ对应的地址给  HandleIRQ 指针所指向的内存,也就是说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;lsl是移位运算
        ldr    r8,[r8]            ;取r8地址中的数据给 r8  .r8实际程序运行对应的地址
        str    r8,[sp,#8]         ;入栈
        ldmfd    sp!,{r8-r9,pc}     ;数据出栈,放入r8~r9 ,PC寄存器 .满递减堆栈
    
    
        LTORG

    这段代码的意思是  HandleEINT0  加上  INTOFFSET  就是真正定义 的中断函数的地址,如果这里不太清楚,需要先了解 2440的中断系统 .

    最后是在C代码中安装中断向量 ,如 pISR_EINT8_23= (U32)IRQ_key_eint;    IRQ_key_eint是定义的函数名,pISR_EINT8_23是定义的一个地址  

    #define pISR_EINT8_23            (*(unsigned *)(_ISR_STARTADDRESS+0x34))   .总结来说  就是把  IRQ_key_eint的地址放在

    HandleEINT8_23中. 我专们把手里的程序调试了一下,当中断产生时  HandleEINT0 中的地址为 0x33FFFF20  ,INTOFFSET  为0x05  即 

    5*4=0x14;  所以获得的地址为 0x30FFFF20+0x14=0x30FFFF34  为pISR_EINT8_23       之前定义的地址. 这个地址中存的数据为我们所编写的中断函数

    的地址  0x30000CE8   .

    ADS的中断过程代码分析完了,下面进行一下MDK下中断过程的分析 ,可以先看看MDK下的的启动代码S3C2440.S  .在启动代码里我们找到这一段 

    ; Copy Exception Vectors to Internal RAM ---------------------------------------
    
                    IF      :DEF:RAM_INTVEC
                    ADR     R8,  Vectors    ; Source
                    LDR     R9, =IRAM_BASE  ; Destination
                    LDMIA   R8!, {R0-R7}    ; Load Vectors 
                    STMIA   R9!, {R0-R7}    ; Store Vectors 
                    LDMIA   R8!, {R0-R7}    ; Load Handler Addresses 
                    STMIA   R9!, {R0-R7}    ; Store Handler Addresses
                    ENDIF

    这里的意思是 如何定义了RAM_INTVEC  ,则表中断向量表 拷贝到内部RAM ,之前一直没有注意到这个,从而导致在MDK下一中断就跑飞了!!

    定义的方法见图:

    做这样修改之后程序就不会跑飞了. 

       这段代码将片上RAM重映射到0x0地址。那么什么情况需要做重映射呢?我们知道CPU启动是从0x0开始的, 也就是异常向量表的起始地址。但是当我们调试

    程序的时候,通常是将程序放在片上的SRAM中,在 MINI2440中,片上SRAM的地址是从0x300000开始的(片上SRAM的初始化文件会把0x300000直接赋给

    PC)。 当调试的程序需要进入中断的时候,PC会自动跳转到异常向量表去,但是实际上物理地址0x0上并没有异 常向量表,所以需要重映射,将片上RAM重映射到

    0x0。否则如果调试过程中产生中断,PC跳到0x0地址找 不到异常向量表,程序就会跑飞.(这里引用自AT91SAM9261启动代码分析) 如果你的程序本身写的没问题

    应该是没有问题的.

      总结这段时间的学习,网上直接关于MDK下用自带启动代码实现中断的几乎是没有,资料相当难找!有的说自带的启动代码有问题(我目前没发现启动代码有什么问题),需要修改,通过修改自带启动代码实现中断,有的是自己写启动代码.有人发现是 MMU的问题,这个问题也正是问题的所在.有需要工程文件的可以留言 ,也可以发页面上的邮箱.

    博文为本人所写,转载请表明出处2440 中断过程分析 (MDK 自带启动代码实现中断)!!  .

  • 相关阅读:
    go语言:go写的日记簿(开源)
    64位pyqt打包生成的python64位的版本,在win32位下无效
    分享:Notepad++ 6.2.3 发布,开源文本编辑器
    PyQt v4 Python Bindings for Qt v4
    python基于http协议编程:httplib,urllib和urllib2
    XP下IIS5运行MVC站点
    你必须要知道的架构知识~第六章 .NET原生态的ORM软件对比
    从微软的DBML文件中我们能学到什么(它告诉了我们什么是微软的重中之重)~七 为DBContext对象应该作为其它实体操作类型的基类,并为它提供统一的提交动作
    MVC最为标准的添加操作(从实体验证到实体入库)
    MVC命名空间中的~UrlHelper中的Action方法告诉我们方法重载的重要性(路由的统一)
  • 原文地址:https://www.cnblogs.com/dreamfactory/p/2976891.html
Copyright © 2020-2023  润新知