ucos-ii移植到MSP430中的一些疑问?
接触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,操作的不多,现在看着舒服多了