UCOS-II OS_CPU_IRQ_ISR函数移植

在有中断发生时,程序跳到OS_CPU_IRQ_ISR处执行。OS_CPU_IRQ_ISR函数在OS_CPU_A.S中。

clip_image002

在分析这个移植代码前,先了解下发生IRQ中断时,ARM的处理流程:

1、 会把当前的CPSR的值拷贝到SPSR_irq

2、 把PC的值拷贝到LR_irq

3、 强制进入IRQ异常模式

4、 强制进入ARM状态

5、 禁止IRQ中断

6、 PC=0X18,跳转到OS_CPU_IRQ_ISR

上面这些都是硬件自动完成的。

在PC跳转到OS_CPU_IRQ_ISR后,已经进入IRQ模式,这时的SP指向的是IRQ模式下的堆栈,也就是说SP的实际物理地址是R13_irq。

下面分析程序:

1:把R1,R2,R3的值保存到IRQ的堆栈,只保存这3个寄存器的原因是下面使用到了这3个寄存器。

2:把当前SP的值保存在R1中

3:因为在保存R1,R2,R3进堆栈时,SP减了12,所以这里让SP+12,重新指向IRQ堆栈的起始位置。

4:LR_irq减4得到的值保存在R2中,LR_irq的值不变。这里减4和ARM的3级流水线取指有关系。

5:把SPSR_irq的值保存进R3,SPSR_irq的值是进入中断前的CPSR值

6:修改CPSR的值,进入系统模式

7:因为系统模式和用户模式的寄存器一样,所以系统模式的SP就是用户模式的SP。把R2的值压入堆栈,这句是保存用户程序的返回PC值

8:保存任务的R12-R4 LR值进堆栈

9:把保存在IRQ堆栈里的R1,R2,R3寄存器的值保存到系统堆栈里,也就保存到用户任务堆栈。对应第1-4条指令就可以看明白。

10:把R0的值保存进堆栈

11:把R3保存的值,也就是SPSR_irq的值保存进堆栈。SPSR_irq的值就是进入中断前的CPSR值。

到这里为止,所有的寄存器值都已经保存到了任务堆栈里。

12:OSIntNesting加1 OSIntNesting是内核为中断嵌套的层数定义的一个全局变量。每进入一次中断,该变量加1,退出一次中断,该变量减一。中断全部处理完,该变量为0

13:判断是否是中断的第一层,如果是,立即把堆栈指针保存到这个任务的任务控制块OS_TCB中。如果有中断嵌套,跳转到OS_CPU_IRQ_ISR_1处执行。

这么做是UCOS中规定的。中断第一层要保存任务堆栈指针,这个好理解,如果发生中断嵌套,就不用再保存任务堆栈指针了,因为中断第一层已保护过。

14:进入IRQ模式,利用IRQ模式下的堆栈来处理中断程序。

15:把函数OS_CPU_IRQ_ISR_Handler()的地址传给R0。OS_CPU_IRQ_ISR_Handler()是执行中断处理的函数,下面会讲到。

16:把当前PC的值保存进LR_irq。作为下面调用OS_CPU_IRQ_ISR_Handler()函数后的返回地址。

17:跳转到OS_CPU_IRQ_ISR_Handler()处执行。

OS_CPU_IRQ_ISR_Handler()不是UCOS-II自带的函数,是用户自己加的。我是在LPC2214上移植的,下面的寄存器都是LPC2214的中断寄存器。函数如下:

void OS_CPU_IRQ_ISR_Handler(void)

{

PFNCT pfnct;

pfnct = (PFNCT)VICVectAddr; /* Read the interrupt vector from the VIC */

while (pfnct != (PFNCT)0) { /* Handle ALL interrupting devices */

(*pfnct)(); /* Call ISR for interrupting device */

pfnct = (PFNCT)VICVectAddr; /* Read the interrupt vector from the VIC */

}

}

VICVectAddr寄存器存的就是中断处理函数的地址,当这个值不为0时,就跳到对应的中断处理函数处执行。这个值为0,说明所有的中断处理函数都已经执行完成,程序返回。

18:进入系统模式

19:调用OSIntExit函数。注意使用BL指令跳转时,会自动把下一条指令地址拷贝到LR中,而使用BX不会。在OSIntExit函数中,OSIntNesting会减1,同时判断是否执行任务调度。如果要进行任务调度,会调用函数OSIntCtxSw();执行OSIntCtxSw()后,就会跳转到新的任务去执行,不会执行后面的指令了。

20:如果没有进行任务调度。就把任务堆栈中的保存的寄存器值全部恢复到寄存器中。在任务中断的断点处继续运行。

发表评论

电子邮件地址不会被公开。 必填项已用*标注