新闻中心

EEPW首页>嵌入式系统>设计应用> uC/OS II的任务切换机理及中断调度优化

uC/OS II的任务切换机理及中断调度优化

作者: 时间:2016-12-01 来源:网络 收藏

  对于这样的设计方式,CPU必须能够:

  • 有相应的CPU寄存器能够模仿SP的一些功能,能使用相应的指令来完成类似SP的一些操作;
  • 作为SP使用的寄存器在编译过程中最好不被编译器默认使用。在IAR的编译器中,有一个选项可以避免在编译过程中使用到R4、R5。

  这两点MSP430都可以做到。

   下面对一个正在运行的优先级为6的任务中断后,会发生的几种情况进行分析。

   1)在中断的处理过程中没有更高优先级的中断产生,即不会产生中断嵌套。
  图3所示为中断发生后对于任务优先级为6的任务堆栈所进行的操作。中断发生后,PC和SR被系统压栈②,对于IAR C编译器来说,会按照复杂度不同的中断服务程序的要求,默认地进行一些寄存器的压栈操作③。因为我们要求的堆栈格式是如图2所示的,我们要把SP调整到 SR后面④,然后进行R4~R15的压栈操作,形成我们所要求的堆栈格式⑤。


  进行任务堆栈的压栈工作以后,就可以调整SP的指针到系统堆栈了,如图4所示。压栈后的SP指向最后一个压栈内容①。我们把SP的值赋值给优先级6任务的TCB->OSTCBStkPtr,以便进行任务调度的时候出栈使用②。接着,就把SP调整到系统堆栈处③。在中断处理过程中,可能会出现压栈的操作,那么这种情况下SP的指针会随之移动。由于现在是中断堆栈中,所以不会破坏任务堆栈的格式。


  由于没有中断嵌套,在中断处理中没有别的中断发生,那么返回的步骤和上述的进栈操作正好相反。在中断处理完了以后,SP会自动回到图4中③的SP位置。接着,系统会查询到优先级最高的任务,然后把SP的指针移到优先级最高的任务的任务堆栈,进行 R15~R4的出栈工作,最后用RETI中断返回指令返回到新的任务。因为我们把所有的任务堆栈都规定成相同的格式,所以它们之间不会产生问题。这里需要注意的是,因为系统在C编译器的中断处理中会对中断进入时默认压栈的寄存器出栈,所以在设计出栈的程序时,要先把这些内容压栈,这样才能正确出栈。

  2)在中断的处理过程中,有别的中断产生,产生中断嵌套。
  如图5所示,由于在处理中断的时候,SP已经被移到系统堆栈去了,只有当中断退出的时候才可能把SP移到别的任务的任务堆栈中。所以在中断的时候进行中断嵌套,那么对于中断的处理和第一次是一样的,所不同的是,这次保存在堆栈中的不是任务运行中的寄存器,而是中断处理中的寄存器,而且是保存在系统堆栈中而不是任务堆栈中。从这里就可以看出优化内存的效果。所有的中断嵌套中的寄存器压栈都压在系统堆栈中,这样对于任务堆栈内存大小的要求大大降低。


  因为uC/OS II在进入中断中,会把全局变量OSIntNesting++;在退出中断的时候,又会把OSIntNesting--。在退出中断进行任务切换之前,uC/OS II会先判断OSIntNesting是否为0,是0才会进行任务调度。当第二中断运行结束以后,退出中断嵌套的时候, OSIntNesting不为0,也就不会进行任务调度。因此,仍旧在系统堆栈出栈,那么系统会继续前面没有完成的中断服务程序。

  接着退出中断的顺序和非中断嵌套的顺序是一样的。在中断处理完以后,SP会自动回到图4中③的SP位置。接着,系统会查询到优先级最高的任务,然后把SP的指针移到优先级最高的任务的任务堆栈。进行R15~R4的出栈工作,最后用RETI中断返回指令返回到新的任务。

  中断的情况基本上就是上述两种。对于有些文献中提到的在中断中会调度到更高优先级的任务的情况,笔者觉得是不应该发生的。因为从上面的分析可以看出,默认的(uC/OS II的设计思路)中断处理会同时对全局变量OSIntNesting进行增减处理,

  以给出是否需要任务调度的条件。那么即使在中断服务程序中把更高优先级的任务就绪,也会等到中断退出以后再进行调度,除非是在中断中直接调用更高优先级的任务函数。但这种方法应该是和uC/OS II的原则相违背的,沿用的是以前前后台设计的思路。

  对于这样的设计方式,时钟节拍的处理方式必须和一般的中断处理方式是一样的。一般来说,MSP430使用WATCHDOG时钟中断作为时钟节拍的产生源。从本质上来说,时钟节拍本身也是中断处理过程,所以对于时钟节拍的处理应该和其它的中断处理过程相同。实际上,在时钟节拍的处理过程中也可能会存在中断嵌套的问题。

  中断堆栈和任务堆栈分离设计的程序流程如图6所示。

4 几点建议

  1. 编写中断程序的时候,有条件尽量使用汇编语言。因为这样可以避免一些编译器自己进行的操作,减少指针调整的次数。
  2. 在用C编写中断服务的时候,因为有些功能必须调用汇编的函数才能实现。调用函数时,有些时候压栈的PC会破坏堆栈的结构。这个时候需要把堆栈进行适当的调整,保证堆栈格式的正确。
  3. 中断处理过程中调用OSIntExit()的时候,由于 uC/OS II的原始设计中SP指针有时是不调整的,所以在OSIntExit()返回了以后,还要判断一下是否中断嵌套。因为有的时候是需要切换任务的。

上一页 1 2 下一页

评论


技术专区

关闭