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的作用也是自动作现场环境处理,而且它的处理是不支持中断嵌套的。
|