uCOS-II是如何避免调整堆栈指针的?

uCOS-II是如何避免调整堆栈指针的? 
 


关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNesting == 1”的原因 ==避免调整堆栈指针
问题概述:
   自从uCOS-II 版本 v2.04 以后(不含v2.04),在所有的中断服务程序中,当处理最外层中断时,那么必须 保存好现场之后,必须马上

加上如下判断

       if( OSIntNesting == 1){
          OSTCBCur->OSTCBStkPtr = 当前的堆栈指针
       }
       以上代码的意思是:当处于最外层中断时,保存被中断任务的堆栈指针。
       注意:是所有的ISR,不论是uCOS-II的系统ISR(在v2.04以后的版本,系统的ISR已经加上了),还是用户的ISR


   这是做是为了在移植中避免调整堆栈指针,减少移植时所需修改的汇编代码量
问题来源:
   出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务原来的低优先

级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。如下图

所示的场景:



┏━━━━━━━━┓                                          ┏━━━━━━━━┓
┃  低优先级任务  ┃                                          ┃  低优先级任务  ┃
┗━━━━━━━━┛                                          ┗━━━━━━━━┛
                   / 在低优先级任务执行过程
                    /中出现中断,任务被打断
                     /|
                     ┏━━━━━━━━┓
                     ┃中断服务程序ISR ┃(已经是最外层中断)
                     ┗━━━━━━━━┛
                                        /
                                         / 中断结束后有高优先级任务出现调
                                          /度高优先任务,原来被中断的任务
                                           /| 继续被中断着
                                            ┏━━━━━━━━┓
                                            ┃  高优先级的任务┃
                                            ┗━━━━━━━━┛

                          需要调整堆栈指针的场景

 

 

问题分析:
   要想理解加上上面两句的原因,不妨假设有下面场景出现:
      void MyTask(void)
      {
        ...
        ...
      }
      该任务在执行过程中被中断打断,下面是它的服务子程序

   void MyISR(void)
      {
       保存现场(PUSHA)
       OSIntEnter();
       // 此时的堆栈指针是正确的,再往下就不对了,应该在此处保存用户任务堆栈指针
            
       OSIntExit();
       恢复现场(POPA)
    中断返回
      }   

 一般的OSIntExit(),大体如下,不论是哪个版本
   
      OSIntExit()
      {
        OS_ENTER_CRITICAL();
       if( OSIntNesting==0 && OSLockNesting == 0 ) {
           找到目前系统中就绪表中优先级最的任务  
      如果不是当前任务,则调度它执行
           OSIntCtxSw();
        }
        OS_EXIT_CRITICAL();
      }

综上所述,任务调用链如下:
  
    MyTask --> MyISR -->
                 ①     OSIntExit -->
                            ②        OS_ENTER_CRITICAL(); ③
                                      OSIntCtxSw();        ④
由用户的堆栈内容如下
 


┃     低端存储器          ┃
┣━━━━━━━━━━━━━┫ <━━━━━ 最后调度器调度高优先级任务时
┃调用OSIntCtxSw的返回地址  ┃<- ④    低优先级任务的堆栈指针指向这里
┣━━━━━━━━━━━━━┫                                         |        
┃ 由OS_ENTER_CRITICAL而保存┃(这两个返回地址都没有用,它们不会返回,  |
┃ CPU内容,具体是由中断方式┃ 所以必须将堆栈指针调整回下面            |
┃ 决定                     ┃<- ③                                    |
┣━━━━━━━━━━━━━┫                                         |
┃  调用OSIntExit的返回地址 ┃<- ②                                    |
┣━━━━━━━━━━━━━┫ <━━━━━ 而真正应该指向这里, <<<-- +
┃                          ┃
┃  被保存的CPU寄存器       ┃/
┃                          ┃ /
┣━━━━━━━━━━━━━┫  /①
┃     中断返回地址         ┃  /
┣━━━━━━━━━━━━━┫ /   
┃      CPU状态字           ┃/
┣━━━━━━━━━━━━━┫
┃      高端存储器          ┃


然而在实际的移植过程中,需要调整的指针偏移量是与编译器相关的,如果想要避免调整,显然一个简单的方法就是在调用OSIntExit之前先把

堆栈指针保存下来,以后调度该用户任务时,直接从此恢复堆栈指针,而不再管实际的堆栈内容了(因为下面的内容相对于调度程序来说已经

没有用处了)


综上所述:所有的中断服务程序(ISR),不论是uCOS-II系统的还是用户的中断服务程序,都必须在保存好现场以后必须加上如下两句
 
   if ( OSIntNesting == 0 ) {
        OSTCBCur->OSTCBStkPtr = 此时的堆栈指针;
   }

当时系统的ISR,自v2.04以后都已经加上了这两句,而用户的ISR则完全由用户来保证加上两句,否则会出现问题,因为此时的OSIntCtwSW已经去掉了调整堆栈指针的指令。

以上就是v2.04以后不需要调整堆栈指针的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值