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