jishanlaike 发表于 2011-2-19 11:37:18

uCOS-II中断嵌套问题

有一个问题需要大侠指导下;
假设
   某MCU具有中断嵌套功能,在进入中断后可以立即开中断。

   已经知道ucos支持中断嵌套,实质是通过OSIntNesting累加来跟踪中断。

现在的问题是:


1.cpu在任务1执行。。。。
2.中断1发生,程序进入中断1,还没有来得及做OSIntNesting++;更高优先级的中断2发生了,
3.中断2开始执行,这时OSIntNesting++;并在本中断2中让更高优先级的任务2就绪。
3.中断2执行末尾,此时OSIntNesting==0,执行任务切换,,,,

问题发生在这里,由于ucos在中断1发生时,没有来得及让OSIntNesting++中断2就发生了;从而导致中断2执行末尾发生了任务切换,这是不允许的,因为中断1还在被中断中。。。。

请问这种一进入中断就允许中断嵌套的CPU,中断程序怎么写呢?琢磨很久,还是不大明白。。

goink 发表于 2011-2-19 12:10:32

CPU_CRITICAL_ENTER();   /* 关全局中断*/
    OSIntNesting++;      /* Tell uC/OS-II that we are starting an ISR            */
CPU_CRITICAL_EXIT();      /* 开全局中断*/

保证了OSIntNesting++; 操作的原子性。

jishanlaike 发表于 2011-2-19 12:38:39

goink 小桂
你好!

如果中断2在 执行 CPU_CRITICAL_ENTER(); 而还没有进入OSIntNesting++;   就发生呢?

goink 发表于 2011-2-19 15:49:41

比如在STM32下
#defineOS_ENTER_CRITICAL(){cpu_sr = OS_CPU_SR_Save();}
#defineOS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}


CPU_SR_Save
      MRS   R0, PRIMASK   ; set prio int mask to mask all (except faults)
      CPSID   I               ;除能PRIMASK(CPSID i)——置位相应的位(就是关中断)
      BX      LR

CPU_SR_Restore                        
      MSR   PRIMASK, R0
      BX      LR

注:
PRIMASK   这是个只有单一比特的寄存器。在它被置1后,就关掉所有可屏蔽的异常,
          只剩下NMI和硬fault可以响应。它的缺省值是0,表示没有关中断。

这就保证了执行 CPU_CRITICAL_ENTER() 时不会有中断发生了呀。

引例:
void SysTickHandler(void)
{
   OS_CPU_SRcpu_sr;


    OS_ENTER_CRITICAL();//保存全局中断标志,关总中断/* Tell uC/OS-II that we are starting an ISR*/
    OSIntNesting++;
    OS_EXIT_CRITICAL();          //恢复全局中断标志

    OSTimeTick();   /* Call uC/OS-II's OSTimeTick(),在os_core.c文件里定义,主要判断延时的任务是否计时到*/

    OSIntExit();//在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换            
}

jishanlaike 发表于 2011-2-19 16:22:00

MRS   R0, PRIMASK   ; set prio int mask to mask all (except faults)
------>中断好像可以在这里发生-------------------------->进入更高级中断------->
      CPSID   I               ;除能PRIMASK(CPSID i)——置位相应的位(就是关中断)

goink 发表于 2011-2-19 20:03:19

是的,有这种可能,所以我感觉上面两句调换一下顺序会好一点。

feng200808 发表于 2011-2-19 21:45:49

回复【楼主位】jishanlaike阿弱
-----------------------------------------------------------------------

对于Cortex-M3,uCOS的任务切换是由pendsv中断实现的,而pendsv中断的优先级最低,
所以即使”中断2执行末尾发生了任务切换“,真正的任务切换也不会发生,只是触发了pendsv中断了而已,
只有中断1执行完后,pendsv中断才会执行,因为pendsv的中断优先级最低。
下面是uCOS,Cortex-M3任务切换的代码:
OSCtxSw
    LDR   R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR   R1, =NVIC_PENDSVSET
    STR   R1,
    BX      LR
OSCtxSw只是触发pendsv中断而已,真正的任务切换在pendsv中断服务程序中,而且pendsv中断的优先级在OSStartHighRdy中被设置为
最低,如OSStartHighRdy:
OSStartHighRdy
    LDR   R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    LDR   R1, =NVIC_PENDSV_PRI
    STRB    R1,

jishanlaike 发表于 2011-2-22 12:48:56

【6楼】 feng200808 :
你好!

是的对于CM3而言,确实是这样,还有晚来中断也会出现这种情况,例如:中断1没有执行任何一条指令,中断2就执行了(中断2是晚到的高优先级任务)

但是:uCOS-II不是专门针对CM3设计的,CM3不会出现这种问题

而有很多的MCU都有中断嵌套功能,只要是中断嵌套的MCU,感觉就会出现这种情况,关键是这些MCU并没有CM3的PendSV这种先进功能啊,这些MCU怎么办呢??

jishanlaike 发表于 2011-2-24 14:51:16

这个命题没有解答么?嘎嘎。。。。。。

feng200808 发表于 2011-2-25 11:40:13

回复【7楼】jishanlaike阿弱
-----------------------------------------------------------------------

如果是这样的话,
(1)在中断1和中断2的末尾可以不进行任务切换的,即OSIntExit()可以不执行,只进行
OS_ENTER_CRITICAL();
OSIntNesting--;
OS_EXIT_CRITICAL();即可,(只在节拍器的中断程序末尾执行OSIntExit())。
(2)节拍器的中断优先级设置到最低。
(3)其实中断1和中断2的服务程序只要不用到和OSIntNesting相关的函数,
OSIntNesting++;和OSIntNesting--;也可以不要,中断程序会更加简洁。


ISR程序中是否处理OSIntNesting,以及在ISR程序末尾是否进行任务切换,可以根据应用而定,并不是非得要处理不可的;
个人之见,欢迎拍砖。。。

jishanlaike 发表于 2011-2-25 12:55:46

feng200808:你的想法很有启发性!

假设有10个中断优先级,有10个中断服务程序与之对应,其中有9个不进行任务切换,那么这9个的优先级必须高于所有另外1个的中断优先级了。。。。

即:不包换任务切换的必须高于有任务切换的,以防止被嵌套,好像只有一个优先级可以进行任务切换。。。。。。。


难道需要建立一个最高优先级的专门用于任务切换的任务?。。。。。。。

feng200808 发表于 2011-2-25 16:48:11

回复【10楼】jishanlaike阿弱
-----------------------------------------------------------------------
“好像只有一个优先级可以进行任务切换。。。。。。。”

恩,的确会是这样,这么做还是有一定的局限性

Chester 发表于 2011-4-24 16:55:57

mark

valley 发表于 2011-4-24 19:01:25

就我所知,arm7/arm9进入中断后其它中断都是被屏蔽的吧,除非清除psr中的中断屏蔽位。
想要中断嵌套的话得手动清除中断屏蔽位,而程序员得负责在这之前做好上下文环境的保护。

micheal_rz 发表于 2011-6-21 17:16:41

uCOS的设计思想就是如果产生中断嵌套,就等到所有的中断处理程序都结束,嵌套层数为1时才进行任务调度。只要按照规则编写中断处理程序就没有问题。

ecomputer 发表于 2011-11-11 10:17:03

对于Cortex-M3,uCOS的任务切换是由pendsv中断实现的,而pendsv中断的优先级最低,
所以即使”中断2执行末尾发生了任务切换“,真正的任务切换也不会发生,只是触发了pendsv中断了而已,
只有中断1执行完后,pendsv中断才会执行,因为pendsv的中断优先级最低。
下面是uCOS,Cortex-M3任务切换的代码:
OSCtxSw
    LDR   R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR   R1, =NVIC_PENDSVSET
    STR   R1,
    BX      LR
OSCtxSw只是触发pendsv中断而已,真正的任务切换在pendsv中断服务程序中,而且pendsv中断的优先级在OSStartHighRdy中被设置为
最低,如OSStartHighRdy:
OSStartHighRdy
    LDR   R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    LDR   R1, =NVIC_PENDSV_PRI
    STRB    R1,



feng200808 分析得比较透彻,即使嵌套由于有PENDSV这种保护机制,也不会出问题,其实发生任务切换是在最后一个中断执行完后,并且中断打开的情况下才发生的

armstrong 发表于 2012-2-23 22:46:15

其实这个问题跟ucos并没有关系,是所有RTOS都会面对的问题。
解决问题的方法是依赖CPU移植代码的,对于Cortex-M3,上面分析过没有问题,因为它是有PendSV和NVIC的。
对于ARM7,ARM9,由于进入IRQ和FIQ硬件会关闭相应的中断,你只要在中断环境里做好现场保护之后,重新打开中断之前,把OSIntNesting用汇编语言加1就可以了。
以我多年经验来断言,ucos系统的不稳定大多是开发者移植的问题、上层应用的设计问题导致的,ucos本身并没有过错,是经得起考验的。

armstrong 发表于 2012-2-23 22:53:41

回复【14楼】micheal_rz
ucos的设计思想就是如果产生中断嵌套,就等到所有的中断处理程序都结束,嵌套层数为1时才进行任务调度。只要按照规则编写中断处理程序就没有问题。
-----------------------------------------------------------------------
对的,CPU移植代码就是要按照这样的设计思想来移植才争正确。
页: [1]
查看完整版本: uCOS-II中断嵌套问题