UCOS-II中OS_CPU_IRQ_ISR移植过程分析
CMP R1,#1 ;if(OSIntNesting==1){
22、BNE %F1;如果是在中断嵌套中,则直接跳转到下面的中断处理函数中
23-25、
LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP;
LDR R5,[R4]
STR SP,[R5]
说明是从任务到中断的过程,也就是只有一个中断产生,不是在中断嵌套中,这时就需要将SP的值保存到任务控制块中。 以上的操作也就完成了任务情景的保存操作,接下来的操作就应该是真正的中断处理函数啦。
27、1 MSR CPSR_c,#IRQMODE|NOINT;实质上是完成CPU模式的切换操作,进入到IRQ模式下。
接下来的实际处理过程就如前面两篇文章中讨论的中断处理过程。
29-30、
LDR R0, =INTOFFSET
LDR R0, [R0]
得到INTOFFSET的值,实际上就是得到偏移量,实质上就是中断号产生中断,通过这个寄存器可以快速的确定在二级向量表中该中断的向量位置,该向量表中就保存了对应中断处理函数的函数地址。
32、LDR R1, IRQIsrVect
43、IRQIsrVect DCD HandleEINT0
这两句说明了我前面的分析,IRQIsrVect实际上就是一个标号,其中存储了HandleEINT0,HandleEINT0又是我们IRQ中断向量的入口地址(前一篇文章已经说明),也就是说HandleEINT0是二级向量表的开始地址。因此此时R1中实际上就保存了HandleEINT0。
33、MOV LR, PC;就是完成简单的保存过程,这个过程实质上就是保存了函数调用的返回地址。
34、LDR PC, [R1, R0, LSL #2];这句代码的意义是将地址R1+R0*4处的内容加载到PC中,也就是实现函数的跳转,即函数的调用过程。其中R1=HandleEINT0,而R0恰好又是一个偏移量,每一个指针的空间是4个字节,那么R1+R0*4地址处刚好就是对应中断号的向量。其中就保存了对应中断函数的地址。因此PC就保存了这个调用函数的入口地址。也就是实现了处理函数调用过程。
35、 MSR CPSR_c,#SVCMODE|NOINT; 执行这句代码的前提就是被调用的函数执行完毕了,相关的入栈出栈操作也已经完成,恢复到了调用前的状态。此时需要将CPU的模式切换到SVC模式下。
36、BL OSIntExit ;这个操作完成了中断的切换,如果不是在中断嵌套中,那么最高优先级的任务就会被执行,进入最高优先的任务之后就不会再返回了,这是UC/OS-II中任务的特点,之后的代码也就不会执行了。这是特别需要注意的。但是如果任务处在中断嵌套中,那么OSIntExit只是减少中断嵌套的次数,并不完成其他的操作。那么这时候就需要恢复之前被中断的任务了,也就是需要完成任务堆栈的弹出操作。
39-41、
LDMFD SP!,{R4} ;POP the tasks CPSR
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^
这几句代码的实现实质上是完成了在中断嵌套中时的任务切换操作。
讨论:
不知道我理解的对不对,我认为这段代码存在一定的问题,具体的问题如下,因为在中断嵌套中,CPU执行的肯定就是中断服务函数,此时的任务处于低优先级的,并不需要我们保存任务的信息。为什么这段代码能够运行的原因我认为主要是因为这种处理的方式是不可能导致中断嵌套问题产生的。因为我们在进入中断以后关闭了中断使能位,不会产生中断嵌套也就看不出问题所在。我认为如果在支持中断嵌套的CPU中,应该首先检测是否在中期嵌套中,如果在中断嵌套中,则不需要任务寄存器的保存,如果不在,则需要保存。
关闭中断的方式避免了中断嵌套产生的可能,这也说明一直需要保存任务的情景,使得这段代码是有效的。
总结:
在讨论ARM的移植过程中,我觉得首先应该搞清楚每一种情况下CPU的工作模式,同时搞清楚寄存器的特殊性,同时搞清楚中断处理的一般过程。
UCOS-IIOS_CPU_IRQ_ISR移植过 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)