最近对比stm32和2440的中断处理,有很多困惑,经过几天的思考和实验终于搞明白了。
stm32和2440虽然都是arm架构,但是stm32在中断上比较特殊,发生不同的中断,硬件上会直接给pc强行赋值,不同的中断对应不同的值。但是2440则是只要有中断就跳到一个固定地址,不论中断是什么跳到的地址都一样。我想这也是为什么stm32在裸机上应用的越来越多的原因之一。(没有深入研究32的中断处理流程,理解有误望告解
)
s3c2440在没有中断向量表时,每次发生中断都要在中断函数中判断一下是什么中断再跳转,因此我
参照stm32的启动文件在自己之前做的启动文件基础上设置了二级向量表实现中断跳转。之前的启动文件可以在前几篇博客下载,mdk自带的启动代码最后会跳到一个_main中做了一些用户看不到的工作,_main还不是开源的,所以启动代码有很多地方不理解,就自己写了一个启动代码除了硬件的初始化,实现了zi段清零和加载程序到sdram执行。这次又添加了中断向量表。
程序的最开始肯定是
第一级的异常向量表,这是由硬件决定的,发生7种异常(还有一种保留)分别强制pc取值:
B Reset_Addr
LDR PC, =Undef_Addr
LDR PC, =SWI_Addr
LDR PC, =PAbt_Addr
LDR PC, =DAbt_Addr
LDR PC, =HandleNotUsed
LDR PC, =IRQ_INT
LDR PC, =FIQ_Addr
在IRQ_INT中实现二级向量表跳转:
IRQ_INT
SUB SP,SP,#4 ;reserved for PC
STMDB SP!,{R0-R1}
LDR R1,=INTOFFSET
LDR R1,[R1]
LDR R0,=VECTOR
ADD R0,R0,R1,LSL #2
LDR R0,[R0]
STR R0,[SP,#8]
LDMIA SP!,{R0-R1,PC}
在程序的最后是中断向量表(只用外部中断举个例子):
VECTOR DCD HandleEINT0
DCD HandleEINT1
DCD HandleEINT2
DCD HandleEINT3
DCD HandleEINT4_7
DCD HandleEINT8_23
EINT_Handler PROC
EXPORT HandleEINT0 [WEAK]
EXPORT HandleEINT1 [WEAK]
EXPORT HandleEINT2 [WEAK]
EXPORT HandleEINT3 [WEAK]
EXPORT HandleEINT4_7 [WEAK]
EXPORT HandleEINT8_23 [WEAK]
HandleEINT0
HandleEINT1
HandleEINT2
HandleEINT3
HandleEINT4_7
HandleEINT8_23
LDR PC, =HALT
ENDP
举例说明下weak的作用,当c文件中声明了HandleEINT0函数,则在vector这个标号代表的地址里存入的是c函数HandleEINT0地址,当c文件中没有HandleEINT0函数时,vector这个标号代表的地址里存入的是本文件中HandleEINT0这个标号代表的地址,也就是LDR PC, =HALT这条指令的地址。(
halt是一段汇编写的蜂鸣器响的死循环)
这样在c语言中只要根据中断表的名字写中断函数就可以了,比如
void HandleEINT8_23()__irq{}(__irq参照上一篇博客)。
最后还要说一下很有迷惑性的细节问题,当我用汇编写了:
TEST
0000:DCD 0X01
0001:EXPORT TEST
在c语言中想引用TEST这个标号地址也就是0的时候,这样写:
exterm int TEST;
int a=TEST;
这时的a=1,想要实现要这样写a=&TEST
想明白了吧!仔细想想c编译的过程,每一个符号对应的都是地址,a=TEST的意思是从TEST地址中取出数放入a地址中,因此即使在汇编中TEST是0,在c语言也会变成1了!!!这个问题是我在用c语言实现中断向量表时遇到的,浪费了好多时间,最后还是决定简化c语言,把初级工作都在启动代码中用汇编实现。
selfsetup.rar
阅读(2526) | 评论(0) | 转发(0) |