微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > ucos-ii移植到MSP430中的一些疑问?

ucos-ii移植到MSP430中的一些疑问?

时间:10-02 整理:3721RD 点击:

      接触msp430已经大半年时间了,闲着没事,打算将ucoss-ii移植到430中。相较于传统的设计模式或者大多数时候,现在mcu处理任务还是循环的处理,没有任何任务管理,对于共享内存资源的管理也没有。当有功能扩展时,在现有的基础上增加太过臃肿,代码复用过多。虽然ucoss-ii已经好多年了,但是经典就是经典,阅读代码是很享受的,而且有助于理解cpu处理机制。

      当然所谓的移植就是copy,copy,copy,毕竟自身水平有限。因为有过移植到cortex-m0内核的经验,很快工程就搭建起来了,本想着程序按照自己预想的执行,但是出现了问题,我的程序“死了”。因为只是阅读过ucos源码,但是要达到精通还是需要些时间,所以没有依据是哪出了问题。所以我列了些可能的疑点。

1.任务堆栈溢出。

2.ucos变量跑飞。

针对问题一:因为我使用的是msp430fr铁电系列,单片机默认的ram是0x1C00-0x23FF,我通过xcl链接文件将fram的2kb当成ram使用,因为430的栈顶指针是从高地址向低地址增长,并且是从ram的结束地址开始。我将任务的堆栈增大了,通过仿真没有解决问题。

针对问题二:既然不是堆栈大小的问题,我就开始跟踪ucos变量。其实阅读过ucos源码后,一些变量的含义很容易理解。这是我的仿真界面:

                                                

       OSTCBTbl任务控制块数组,OSTCBPrioTbl里面包含任务控制块指针,和就绪表是对应的,然后就是任务的优先级等。经过查看跟踪Stack栈内容,也未发现问题。然后无意中看到我cpu的sr寄存器中GIE被关了,而且莫名其妙的cpu的oscoff和cpuoff,及scg0,scg1置位了。这让我很纳闷,GIE关了任务肯定不能调度,但是我也没有主动去进入低功耗模式。因为我的空闲任务中的钩子函数是空的,那么程序哪里会主动关呢?      

       整整3天就是在想,上网百度了也没有结果。不过我只能怀疑我的OSTimeTick()函数了,因为430没有可屏蔽的定时器,不像cortex-m0内核,有个system定时器,优先级很高。就只能选用了开门狗定时器了。也怪自己手残,觉得定时器中断处理应该和cortex-m0差不多,就这样处理了:

          #pragmavector=WDT_VECTOR__interrupt

          void WDT_ISR(void)

          {  

              OS_CPU_SR cpu_sr;              //使用方式3  

              OS_ENTER_CRITICAL();  

              OSIntNesting++;                 //中断嵌套层数  

              OS_EXIT_CRITICAL();  

              OSTimeTick();  

              OSIntExit();                          //中断级任务调度

          }

但是在430Os_cpu_a.s43中,中断函数是这样实现的,使用汇编语言,因为汇编不是很熟,c语言看着舒服。经过对比,这是处理最大的区别:

          mov.w    &OSTCBCur, R13         

          mov.w    SP, 0(R13)mov.w    &OSISRStkPtr, SP
为什么中断处理的时候使用到了主堆栈,大家可以看这个函数

          OSStartHighRdy            

                call     #OSTaskSwHook            

                mov.b    #1, &OSRunning                    

                mov.w    SP, &OSISRStkPtr                              

               mov.w    &OSTCBHighRdy, R13                 

               mov.w    @R13, SP            

               POPALL                                          

               reti

       函数OSStartHighRdy是在ucos初始化ucos变量和创建至少一个任务空闲任务,在osstart中调用的,说白了就是第一次调用优先级最高的任务,而OSISRStkPtr也就保存了程序的主堆栈,在没有申请局部量的情况下,他应该跟我们普通的main里的栈顶地址是一样的。这个OSISRStkPtr的作用就在这体现了,但是我也有疑问了,为什么在执行中断任务的时候用了任务的栈就会出现如此大的问题。这是我这次调试过程中最大的疑问?因为水平有限,对430内核不是很了解,cortex-m0内核也不是很懂。之前用cortex-m0调试没关注到这块,请大神为我解答。这是430TICK ISR函数的注释:但我还是不太明白为什么不能用任务的堆栈呢?

; Notes      : 1) The following C pseudo-codedescribes the operations being performed in the code below.;;                                 

                 Save all the CPU registers;                 

                 if (OSIntNesting == 0) {;                    

                              OSTCBCur->OSTCBStkPtr =SP;;                     

                              SP  = OSISRStkPtr;                  /* Use the ISR stack from now on           */;                 

                  };                 

                  OSIntNesting++;;                 

                  Enable interrupt nesting;                     /* Allow nesting of interrupts(if needed) */;                                                        

                  Clear the interrupt source;;                 

                  OSTimeTick();                                      /* Call uC/OS-II'stick handler            */;                                 

                  DISABLE generalinterrupts;                 /* Must DIbefore calling OSIntExit()      */;                  

                  OSIntExit();;                 

                  if (OSIntNesting == 0) {;                     

                  SP =OSTCBHighRdy->OSTCBStkPtr;       /*Restore the current task's stack       */;                 

                  };                 

                 Restore the CPU registers;                 

                 Return from interrupt.;;              

                 2) ALL ISRs should be writtenlike this!;;              

                 3) You MUST disable generalinterrupts BEFORE you call OSIntExit() because an interrupt ;                        

                 COULD occur just asOSIntExit() returns and thus, the new ISR would save the SP of ;                              

                 the ISR stack and NOT the SPof the task stack.  This of course willmost likely cause;                  

                 the code to crash.  By disabling interrupts BEFORE OSIntExit(),interrupts would be;                  

                 disabled when OSIntExit()would return.  This assumes that you areusing OS_CRITICAL_METHOD;                                

                 #3 (which is the preferedmethod).;;              

                 4) If you DON'T use a separateISR stack then you don't need to disable general interrupts ;                  

                 just before callingOSIntExit().  The pseudo-code for an ISRwould thus look like this:;;                  

                 Save all the CPU registers;                 

                 if (OSIntNesting == 0) {;                     

                 OSTCBCur->OSTCBStkPtr =SP;;                 

                 };                 

                 OSIntNesting++;;                 

                 Enable interrupt nesting;                 /* Allow nesting of interrupts (ifneeded) */;                 

                 Clear the interrupt source;;                 

                 OSTimeTick();                                  /* Call uC/OS-II'stick handler            */;                             

                 OSIntExit();;                 

                 Restore the CPU registers;                 

                 Return interrupt.;


; Notes      : 1) The following C pseudo-code describes the operations being performed in the code below.
;
;                 Save all the CPU registers
;                 if (OSIntNesting == 0) {
;                     OSTCBCur->OSTCBStkPtr = SP;
;                     SP                    = OSISRStkPtr;  /* Use the ISR stack from now on           */
;                 }
;                 OSIntNesting++;
;                 Enable interrupt nesting;                 /* Allow nesting of interrupts (if needed) */
;                 Clear the interrupt source;
;                 OSTimeTick();                             /* Call uC/OS-II's tick handler            */
;                 DISABLE general interrupts;               /* Must DI before calling OSIntExit()      */
;                 OSIntExit();
;                 if (OSIntNesting == 0) {
;                     SP = OSTCBHighRdy->OSTCBStkPtr;       /* Restore the current task's stack        */
;                 }
;                 Restore the CPU registers
;                 Return from interrupt.
;
;              2) ALL ISRs should be written like this!
;
;              3) You MUST disable general interrupts BEFORE you call OSIntExit() because an interrupt
;                 COULD occur just as OSIntExit() returns and thus, the new ISR would save the SP of
;                 the ISR stack and NOT the SP of the task stack.  This of course will most likely cause
;                 the code to crash.  By disabling interrupts BEFORE OSIntExit(), interrupts would be
;                 disabled when OSIntExit() would return.  This assumes that you are using OS_CRITICAL_METHOD
;                 #3 (which is the prefered method).
;
;              4) If you DON'T use a separate ISR stack then you don't need to disable general interrupts
;                 just before calling OSIntExit().  The pseudo-code for an ISR would thus look like this:
;
;                 Save all the CPU registers
;                 if (OSIntNesting == 0) {
;                     OSTCBCur->OSTCBStkPtr = SP;
;                 }
;                 OSIntNesting++;
;                 Enable interrupt nesting;                 /* Allow nesting of interrupts (if needed) */
;                 Clear the interrupt source;
;                 OSTimeTick();                             /* Call uC/OS-II's tick handler            */
;                 OSIntExit();
;                 Restore the CPU registers
;                 Return from interrupt.

你这排版有点乱啊

            RSEG    CODE                    ; Program code
OSStartHighRdy
            call     #OSTaskSwHook
            mov.b    #1, &OSRunning         ; kernel running
            mov.w    SP, &OSISRStkPtr       ; save interrupt stack              
            mov.w    &OSTCBHighRdy, R13     ; load highest ready task stack
            mov.w    @R13, SP
            POPALL                          ; pop all registers
            
            reti                            ; emulate return from interrupt

调用主程序堆栈
            mov.w    &OSTCBCur, R13         ;     save task stack
            mov.w    SP, 0(R13)
            mov.w    &OSISRStkPtr, SP       ;     load interrupt stack   

自己手残写的
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
{
  OS_CPU_SR  cpu_sr;
  OS_ENTER_CRITICAL();
  OSIntNesting++;
  OS_EXIT_CRITICAL();
  OSTimeTick();
  OSIntExit();
}

我也不想这样。又不可以重新排版。

可以选择重新编辑的

3q,操作的不多,现在看着舒服多了

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top