ATMEL精妙的IRQ中断处理过程——牛X
从栈地址开始,栈顶为AT91SAM7S64的16K片内RAM尽头0x00204000 IRQ_STACK_SIZE = 3*8*4 FIQ_STACK_SIZE = 0x004 ABT_STACK_SIZE = 0x004 UND_STACK_SIZE = 0x004 SVC_STACK_SIZE = 0x800 SYS_STACK_SIZE = 0x400
irq栈为什么用3*8*4=96B呢?因为irq最多8级嵌套,ARM字长4B,而3,是由于每次进栈均破坏了3个寄存器r0、spsr、lr,所以需要压栈保存的也就是3。计算十分精准,没有一个字浪费,这是AT第一牛X的地方。
当irq发生时,下列操作处理器自动完成: 1。r14(irq)=返回地址 2。spsr(irq)=cpsr(中断发生前的模式) 3。改cpsr,成模式为irq,禁止irq中断。 4。设pc,跳转到0x00000018去
下面看中断0x00000018指向的irq_handle代码:
;因为要继续调用函数,lr会被冲掉,所以压irq栈 sub lr,lr,#4 stmfd sp!,{lr}
;将r0和spsr压irq栈,因为下面用到r0,spsr mrs r14,spsr stmfd sp!,{r0,r14}
;写IVR,支持保护模式,普通模式无效 ;释放NIRQ,清除保护模式下中断源 ldr r14,=AT91C_BASE_AIC ldr r0,[r14,#AIC_IVR] str r14,[r14, #AIC_IVR]
;允许中断嵌套,由irq模式切换入svc模式 msr cpsr_c, #ARM_MODE_SVC
;保存scratch和被使用到的寄存器、lr入svc堆栈 stmfd sp!, {r1-r3, r12, r14}
;跳转到AIC_IVR指向的中断服务程序地址 mov r14,pc bx r0
;恢复scratch、被用到的寄存器、lr ldmia sp!,{r1-r3, r12, r14}
;禁止irq中断嵌套,由svc切换到irq模式。 msr cpsr_c,#I_BIT | ARM_MODE_IRQ
;写AIC_EOICR ldr r14,=AT91C_BASE_AIC str r14,[r14, #AIC_EOICR]
;恢复spsr、r0 ldmia sp!,{r0, r14} msr spsr_cxsf, r14
;中断返回 ldmia sp!, {pc}^
以上就是全部,让我惊叹的是如上做法支持了中断嵌套,想了想,自己以前搞的东西还真是全部回避回去了,也就是说,以前各个中断并没有优先级区分,进了中断就关门i->I。中断服务程序执行完了再打开,优点是简单明了,缺点是中断服务程序必须迅速处理完.
相关链接:https://bbs.21ic.com/club/bbs/list.asp?boardid=48&t=2581607&tp=ATMEL%u7CBE%u5999%u7684IRQ%u4E2D%u65AD%u5904%u7406%u8FC7%u7A0B%u2014%u2014%u725BX |