首先我们看中断处理函数的安装过程!
1.我们定义中断处理函数,以pISR_EINT0为例,将中断处理函数的地址赋予pISR_EINT0 =(U32)isrEINT0;
2.查找宏定义为#define pISR_EINT0 (*(unsigned*)(_ISR_STARTADDRESS+0x20)
3.在_ISR_STARTADDRESS开始处存放的是如:
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
形式的代码,HandleReset # 4意思是预留一个四字节的变量,该变量的标号是HandleRest,不巧的是第0x20位刚好是handlEINT0,那么现在我们就可以把C语言的中断处理函数跟该地址的内容联系起来了
现在请记住HandleENT0标号处的内容已经是你写的C语言的中断处理函数的入口地址了,那么我们接下来看:
当发生了中断后,到底发生了什么!
1.当中断发生时,我们有关的中断引脚有效,硬件自动跳转到从0地址开始的中断向量表如
b HandlerIRQ ;这是一个标签!在宏定义中展开为:
HandlerIRQ
sub sp,sp,#4 ; 预留一个用来存放PC地址
stmfd sp!,{r0} ; 保存R0,因为下面使用了R0
ldr r0,=HandleIRQ ; 将HandleIRQ的地址装载到R0
ldr r0,[r0] ; 取HandleIRQ处的内容
str r0,[sp,#4] ; 将取到的内容保存到刚才预留的地方
ldmfd sp!,{r0,pc} ; 弹出堆栈,跳转到HandleIRQ
2.那么HanleIRQ处的内容是什么?我们可以在启动代码中看到这么一段:
ldr r0,=HandleIRQ ;
ldr r1,=IsrIRQ ;
str r1,[r0] ;
显然是把IsrIRQ的地址安装到了HandleIRQ处,所以现在跳转到IsrIRQ处
3. IsrIRQ处又有:
IsrIRQ
sub sp,sp,#4 ; 预留保存PC的空间
stmfd sp!,{r8-r9} ;保存r9 r8
ldr r9,=INTOFFSET ; INTOFFSET 寄存器保存着当前是哪个IRQ中断,例如 0代表着 HandleEINT0,1代表HandleEINT1
ldr r9,[r9] ;取寄存器的值,即到底是谁发生了中断
ldr r8,=HandleEINT0 ;我们终于看到了HandleEINT0
add r8,r8,r9,lsl #2 ;计算具体的地址
ldr r8,[r8] ;将地址处的内容,也就是中断处理函数的地址送至r8
str r8,[sp,#8] ; 保存了2个寄存器R8 R9 ,所以SP下移了8位 ,该句主要是把中断处理函数的地址送至预先保留的4字节空间
ldmfd sp!,{r8-r9,pc} ; 恢复寄存器,弹出到PC,并跳转到该处执行
|