分享

s3c44b0与s3c2410的多重中断的实现

 BeautymengRoom 2013-12-12

s3c44b0与s3c2410的多重中断的实现

作者:蔡伦辉


写在前面

作者一直支持GPL的精神。允许任何人自由使用、转载、复制和再分发,但必须保留作者署名,必须保证全文完整转载,包括完整的版权声明。

由于作者水平有限,因此不能保证文章内容准确无误,请批判阅读。如果你发现任何错误或对文章内容有任何建议,欢迎你与我联系:
Email:
caiallen@tom.com  QQ群: 14765968


最近因为公司项目忙,好久没更新这里了。也因为项目,才发现原来ARM 的bootloader默认是不支持中断嵌套的,所以必须得自己实现。同时也发现,44b0有向量中断和非向量中断之分,而2410是没有向量中断的。也许这样说并不准确。因为对2410来说,它有:

 

    b    ResetHandler    ;0x00000000 
    b    HandlerUndef    ;0x00000004 handler for Undefined mode    
    b    HandlerSWI      ;0x00000008 handler for SWI interrupt    
    b    HandlerPabort   ;0x0000000c handler for PAbort            
    b    HandlerDabort   ;0x00000010 handler for DAbort            
    b    .               ;0x00000014     

    b    HandlerIRQ      ;0x00000018 handler for IRQ interrupt     
    b    HandlerFIQ      ;0x0000001c handler for FIQ interrupt

    这几个地址存放的就是向量表。然而它又不像44b0存在以下地址的向量表:

;44b0的中断向量表

ResetEntry

  b ResetHandler ;for debug

  b HandlerUndef ;handlerUndef

  b HandlerSWI ;SWI interrupt handler

  b HandlerPabort ;handlerPAbort

  b HandlerDabort ;handlerDAbort

  b . ;handlerReserved

  b HandlerIRQ

  b HandlerFIQ

VECTOR_BRANCH

  ldr pc,=HandlerEINT0 ;mGA 0x20

  ldr pc,=HandlerEINT1 ;

  ldr pc,=HandlerEINT2 ;

  ldr pc,=HandlerEINT3 ;

  ldr pc,=HandlerEINT4567 ;

  ldr pc,=HandlerTICK ;mGA 0x34

  b .

  b .

  ldr pc,=HandlerZDMA0 ;mGB 0x40

  ldr pc,=HandlerZDMA1 ;

  ldr pc,=HandlerBDMA0 ;

  ldr pc,=HandlerBDMA1 ;

  ldr pc,=HandlerWDT ;

  ldr pc,=HandlerUERR01 ;mGB 0x54

  b .

  b .

  ldr pc,=HandlerTIMER0 ;mGC 0x60

  ldr pc,=HandlerTIMER1 ;

  ldr pc,=HandlerTIMER2 ;

  ldr pc,=HandlerTIMER3 ;

  ldr pc,=HandlerTIMER4 ;

  ldr pc,=HandlerTIMER5 ;mGC 0x74

  b .

  b .

  ldr pc,=HandlerURXD0 ;mGD 0x80

  ldr pc,=HandlerURXD1 ;

  ldr pc,=HandlerIIC ;

  ldr pc,=HandlerSIO ;

  ldr pc,=HandlerUTXD0 ;

  ldr pc,=HandlerUTXD1 ;mGD 0x94

  b .

  b .

  ldr pc,=HandlerRTC ;mGKA 0xa0

  b .

  b .

  b .

  b .

  b . ;mGKA

  b .

  b .

  ldr pc,=HandlerADC ;mGKB 0xc0

  b . ;

  b . ;

  b . ;

  b . ;

  b . ;mGKB

  b .

  b .

  ldr pc,=EnterPWDN ;0xe0=EnterPWDN


    这里就必须讲一下向量中断模式和非向量中断模式的概念 向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址,函数中,节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0,则在0xC0处放如下代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会自动跳转到HandlerADC函数中。

    非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt pending寄存器中对应标志位置位 然后跳转到位于0x18处的统一中断函数中, 该函数通过读取interrupt pending寄存器中对应标志位来判断中断源,并根据优先级关系再跳到对应中断源的处理代码中。

    现在说回中断嵌套。要想实现中断可嵌套并安全正确地返回,现场保护是关键。在IRQ中断发生时,先在IRQ模式保护现场,然后转到SVC模式把现场环境拷贝到SVC的堆栈,处理IRQ中断,并在这个模式下恢复现场。下面是我对2410的bootloader做了修改,实现了IRQ中断嵌套:

;*****************************************************************************
;**                                                                         **
;** IsrIRQ                                                                  **
;**                                                                         **
;真正的非向量IRQ中断入口
;*****************************************************************************
IsrIRQ
;=============================================================================        
;(1)在中断模式下保护被中断的模式的环境
;1-1 lr-4压栈,lr-4才是被中断的模式的PC返回地址
;=============================================================================        
    SUBS          LR,        LR,        #4
    STMFD        {LR}

;=============================================================================        
;1-2 再压入lr,仅作占位,该值在被中断的模式的lr的寄出器中    
;=============================================================================        
    STMFD        {LR}

;=============================================================================        
;1-3 保存R0~R12的值。这样在后面的算法里可以使用R0~R12
;=============================================================================        
    STMFD        {R0-R12}

;=============================================================================        
;1-4 保存SPSR
;=============================================================================        
    MRS           R0,        SPSR
    STMFD        {R0}
    
;=============================================================================        
;1-5 恢复IRQ模式下的堆栈指针,指向被中断前的位置
;=============================================================================        
    ADD        R3,        SP,        #64
    MOV        SP,        R3

;=============================================================================        
;(2)切换到SVC模式,利用SVC的堆栈保存现场,并在四J较麓?鞩RQ中断
;=============================================================================        
    MSR        CPSR_cxsf,    #SVCMODE|I_BIT
    
;=============================================================================        
;(3)拷贝现场
;=============================================================================        
    LDMDB        {R0}
    STMFD        {R0}
    LDMDB        {R0}
    STMFD        {LR}
    LDR          R1,        =56
0
    LDMDB        {R0}
    STMFD        {R0}
    SUBS         R1,        R1,        #4
    BNE          %B0
    
;=============================================================================        
;(4) 设置中断入口
;=============================================================================        
    LDR        R9,        =INTOFFSET
    LDR        R9,        [R9]        ;读入中断偏移码,确定中断源
    LDR        R8,        =HandleEINT0;二级跳转表的首地址    
    ADD        R8,        R8,        R9,        LSL #2    ;R8=R8+R9X4得到相应的中断入口地址,
    LDR        R8,        [R8]                    ;把中断偏移地址和基地址相加
    
    MOV        LR,        PC
    ADD        LR,        LR,        #4
    MOV        PC,        R8

;=============================================================================        
;(5) 中断返回后,在恢复现场前,屏蔽所有IRQ中断
;=============================================================================        
    MRS        R0,        CPSR
    ORR        R0,        R0,        #0x80
    MSR        CPSR_c,    R0
    
;=============================================================================        
;(6) 恢复现场
;=============================================================================    
    LDMFD      {R0}
    MSR        SPSR_cxsf,        R0
    LDMFD      {R0-R12,LR,PC}^

    44b0的非向量中断的实现与2410的类似,因为我使用的是44b0的向量中断,所以,我把下面的:

    MACRO      

$HandlerLabel HANDLER $HandleLabel 

$HandlerLabel
   sub     sp,sp,#4        

   stmfd   sp!,{r0}        

   ldr     r0,=$HandleLabel
   ldr     r0,[r0]         

   str     r0,[sp,#4]      

   ldmfd   sp!,{r0,pc}     

    MEND

 

修改为:

;=============================================================================        
;(1)在中断模式下保护被中断的模式的环境
;1-1 lr-4压栈,lr-4才是被中断的模式的PC返回地址
;=============================================================================        
    SUBS        LR,        LR,        #4
    STMFD      {LR}

;=============================================================================        
;1-2 再压入lr,仅作占位,该值在被中断的模式的lr的寄出器中    
;=============================================================================        
    STMFD      {LR}

;=============================================================================        
;1-3 保存R0~R12的值。这样在后面的算法里可以使用R0~R12
;=============================================================================        
    STMFD      {R0-R12}

;=============================================================================        
;1-4 保存SPSR
;=============================================================================        
    MRS        R0,        SPSR
    STMFD      {R0}
    
;=============================================================================        
;1-5 恢复IRQ模式下的堆栈指针,指向被中断前的位置
;=============================================================================        
    ADD        R3,        SP,        #64
    MOV        SP,        R3

;=============================================================================        
;(2)切换到SVC模式,利用SVC的堆栈保存现场,并在此模式下处理IRQ中断
;=============================================================================        
    MSR        CPSR_cxsf,    #SVCMODE|I_BIT
    
;=============================================================================        
;(3)拷贝现场
;=============================================================================        
    LDMDB        {R0}
    STMFD        {R0}
    LDMDB        {R0}
    STMFD        {LR}
    LDR          R1,        =56
0
    LDMDB        {R0}
    STMFD        {R0}
    SUBS         R1,        R1,        #4
    BNE          %B0
    
;=============================================================================        
;(4) 设置中断入口
;=============================================================================        
    LDR        R9,        =$HandleLabel
    LDR        R9,        [R9]        ;读入中断偏移码,确定中断源
    MOV        LR,        PC
    ADD        LR,        LR,        #4
    MOV        PC,        R9

;=============================================================================        
;(5) 中断返回后,在恢复现场前,屏蔽所有IRQ中断
;=============================================================================        
    MRS        R0,        CPSR
    ORR        R0,        R0,        #0x80
    MSR        CPSR_c,    R0
    
;=============================================================================        
;(6) 恢复现场
;=============================================================================    
    LDMFD      {R0}
    MSR        SPSR_cxsf,        R0
    LDMFD      {R0-R12,LR,PC}^

注意:当使用上面的中断嵌套处理时,C语言中中断服务程序不能再使用__irq关键字,因为上面已经作了现场环境的保护处理,而__irq的作用也是自动作现场环境处理,而且它的处理是不支持中断嵌套的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多