- 论坛徽章:
- 0
|
最近因为公司项目忙,好久没更新这里了。也因为项目,才发现原来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的堆栈保存现场,并在此模式下处理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, =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, #8
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, #8
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}^
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/51650/showart_512010.html |
|