• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

uCOS 2.00 在TMS320F2812上的移植完整攻略

本人最近在将uCOS(2.00) 移植到DSP(TMS320F2812)上时,碰到不少问题和故障。从网上下载了不少关于移植到2812上的范例,并且有一份2812开发板上的uCOS范例,无一意外的都有严重BUG。本人经过多次试验和验证,制作出一个相对完整的版本,供大家使用和评价。此版本目前尚未发现问题,但不代表没有BUG,请大家使用时注意。

移植的文件包含如下几个文件:“os_IntSw.src”、“ os_StartHighRdy.src”、“ os_Sw.src”、“os_TickISR.src”、“ os_cpu_c.c”共5个文件。文件内容包含在附录中。另说明,本人系统中,周期中断使用的是T2定时器,因此os_TickISR函数中没有对ACK清零的汇编代码,请大家注意。

对汇编文件,发现2个BUG,添加了一些代码,基本如下:

PUSH AR1H:AR0H

PUSH XAR2

PUSH XAR3

PUSH XAR4

PUSH XAR5

PUSH XAR6

PUSH XAR7

PUSH XT

ASP

PUSH DP:ST1

对应有:

POP DP:ST1

NASP

POP XT

POP XAR7

POP XAR6

POP XAR5

POP XAR4

POP XAR3

POP XAR2

POP AR1H:AR0H

BUG一:

“ POP XT

POP XAR7

POP XAR6

POP XAR5

POP XAR4

POP XAR3

POP XAR2

POP AR1H:AR0H ”为手工保存CPU核心的通用寄存器,不添加此代码,线程之间或中断调用后,会出现异常,此为发现的第1个BUG,添加此代码后解决。这个也为uCOS的基本要求,即完整保存CPU核心的通用寄存器,没有此代码,uCOS将不能正常运行。

全部回复(4)
正序查看
倒序查看
add222
LV.4
2
2014-01-15 16:09

BUG二:

ASP

PUSH DP:ST1

对应有:

POP DP:ST1

NASP

本人在解决第1个问题后,在中断中调用系统信号量函数,发现一调用,系统就崩溃了,经过试验,发现是堆栈指针对齐的问题,即ASP 和 NASP 造成的。ASP受ST1中的一个位控制,所以添加此代码, 保存ST1。同时保存DP1是因为要保证堆栈地址为偶数地址,其实保存DP不起什么作用,仅仅是用来对齐堆栈地址为偶数地址,没有其他的意思。

在os_cpu_c.c文件中,也作了些修改,如下:

void *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt)

{

INT16U *stk;

INT16U temp;

opt = opt; /* 'opt' is not used, prevent warning */

stk = (INT16U *)ptos; /* Load stack pointer */

temp = ((INT32U)pdata)&0x0000ffff; /* Simulate call to function with argument */

*stk++ = (INT16U)temp; /* 保存低16位 */

temp = ((INT32U)pdata)>>16; /* Simulate call to function with argument */

*stk++ = (INT16U)(temp); /* 保存高16位*/

*stk++ = 0x0000; /* ST0 = 0x1111 */

*stk++ = 0x0000; /* T = 0x0000 */

*stk++ = 0x0000; /* AL = 0x3333 */

*stk++ = 0x0000; /* AH = 0x2222 */

*stk++ = 0x0000; /* PL = 0x5555 */

*stk++ = 0x0000; /* PH = 0x4444 */

*stk++ = 0x0000; /* AR0 = 0x7777 */

*stk++ = 0x0000; /* AR1 = 0x6666 */

*stk++ = 0x0A0A; /* ST1 = 0x080B */

*stk++ = 0x0000; /* DP = 0x8888 */

*stk++ = 0x2003; /* IER = 0xBBBB */

*stk++ = 0x2003; /* DBGSTAT = 0xAAAA */

temp = ((INT32U)task)&0x0000ffff;

*stk++ = (INT16U)temp; /* 保存低16位 */

temp = ((INT32U)task)>>16; /* Save task entry */

*stk++ = (INT16U)(temp); /* 保存高16位 */

// PUSH RPC

temp = ((INT32U)task)&0x0000ffff; /* RPCL = 0xCCCC */

*stk++ = (INT16U)temp; /* 保存低16位 */

temp = ((INT32U)task)>>16; /* RPCH = 0xCCCC */

*stk++ = (INT16U)(temp); /* 保存高16位*/

/*

下为手工保存的寄存器

PUSH AR1H:AR0H

PUSH XAR2

PUSH XAR3

PUSH XAR4

PUSH XAR5

PUSH XAR6

PUSH XAR7

PUSH XT

PUSH ST1:DP

*/

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0000; /* 保存高16位 */

*stk++ = 0x0A0A; /* ST1 */

*stk++ = 0x0000; /* DP */

stk++;

return ((void *)stk);

}

文件中比较重要的地方都以红色作了标记,这里特别说明:

temp = ((INT32U)pdata)&0x0000ffff; /* Simulate call to function with argument */

*stk++ = (INT16U)temp; /* 保存低16位 */

temp = ((INT32U)pdata)>>16; /* Simulate call to function with argument */

*stk++ = (INT16U)(temp); /* 保存高16位*/

这个好像没什么用,这样做只是为了避免编译时出现告警(和原来比较)。

*stk++ = 0x0A0A; /* ST1 = 0x080B */

这个特别重要。因为进入任务后,中断必须都是开着的,这个值直接用来设置ST1,详细见ST1的位说明。任务在第一次进入时,NASP指令不能起作用也由这里控制(任务堆栈一般为偶地址)。总中断是由ST1来控制的,因此,在进入任务前,你开关总中断都是无意义的操作,只有这里才是开总中断的地方,要特别注意。当然,你也可以在每个任务开始设置总中断,但那样比较复杂。

0
回复
add222
LV.4
3
2014-01-15 16:09
@add222
BUG二:ASPPUSHDP:ST1对应有:POPDP:ST1NASP本人在解决第1个问题后,在中断中调用系统信号量函数,发现一调用,系统就崩溃了,经过试验,发现是堆栈指针对齐的问题,即ASP和NASP造成的。ASP受ST1中的一个位控制,所以添加此代码,保存ST1。同时保存DP1是因为要保证堆栈地址为偶数地址,其实保存DP不起什么作用,仅仅是用来对齐堆栈地址为偶数地址,没有其他的意思。在os_cpu_c.c文件中,也作了些修改,如下:void*OSTaskStkInit(void(*task)(void*pd),void*pdata,void*ptos,INT16Uopt){INT16U*stk;INT16Utemp;opt=opt;/*'opt'isnotused,preventwarning*/stk=(INT16U*)ptos;/*Loadstackpointer*/temp=((INT32U)pdata)&0x0000ffff;/*Simulatecalltofunctionwithargument*/*stk++=(INT16U)temp;/*保存低16位*/temp=((INT32U)pdata)>>16;/*Simulatecalltofunctionwithargument*/*stk++=(INT16U)(temp);/*保存高16位*/*stk++=0x0000;/*ST0=0x1111*/*stk++=0x0000;/*T=0x0000*/*stk++=0x0000;/*AL=0x3333*/*stk++=0x0000;/*AH=0x2222*/*stk++=0x0000;/*PL=0x5555*/*stk++=0x0000;/*PH=0x4444*/*stk++=0x0000;/*AR0=0x7777*/*stk++=0x0000;/*AR1=0x6666*/*stk++=0x0A0A;/*ST1=0x080B*/*stk++=0x0000;/*DP=0x8888*/*stk++=0x2003;/*IER=0xBBBB*/*stk++=0x2003;/*DBGSTAT=0xAAAA*/temp=((INT32U)task)&0x0000ffff;*stk++=(INT16U)temp;/*保存低16位*/temp=((INT32U)task)>>16;/*Savetaskentry*/*stk++=(INT16U)(temp);/*保存高16位*///PUSHRPCtemp=((INT32U)task)&0x0000ffff;/*RPCL=0xCCCC*/*stk++=(INT16U)temp;/*保存低16位*/temp=((INT32U)task)>>16;/*RPCH=0xCCCC*/*stk++=(INT16U)(temp);/*保存高16位*//*下为手工保存的寄存器PUSHAR1H:AR0HPUSHXAR2PUSHXAR3PUSHXAR4PUSHXAR5PUSHXAR6PUSHXAR7PUSHXTPUSHST1:DP*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0000;/*保存高16位*/*stk++=0x0A0A;/*ST1*/*stk++=0x0000;/*DP*/stk++;return((void*)stk);}文件中比较重要的地方都以红色作了标记,这里特别说明:temp=((INT32U)pdata)&0x0000ffff;/*Simulatecalltofunctionwithargument*/*stk++=(INT16U)temp;/*保存低16位*/temp=((INT32U)pdata)>>16;/*Simulatecalltofunctionwithargument*/*stk++=(INT16U)(temp);/*保存高16位*/这个好像没什么用,这样做只是为了避免编译时出现告警(和原来比较)。*stk++=0x0A0A;/*ST1=0x080B*/这个特别重要。因为进入任务后,中断必须都是开着的,这个值直接用来设置ST1,详细见ST1的位说明。任务在第一次进入时,NASP指令不能起作用也由这里控制(任务堆栈一般为偶地址)。总中断是由ST1来控制的,因此,在进入任务前,你开关总中断都是无意义的操作,只有这里才是开总中断的地方,要特别注意。当然,你也可以在每个任务开始设置总中断,但那样比较复杂。

uCOS 2.00 在TMS320F2812上的移植完整攻略

*stk++ = 0x2003; /* IER = 0xBBBB */

*stk++ = 0x2003; /* DBGSTAT = 0xAAAA */

这个也很重要,是中断允许位IER。原来是设置的0xFFFF,即任务开始时,所有的中断允许开着的,这必将和你的设想不一样。因此这个应该根据你的系统使用的中断的多少来自己确定,这个也是整个C文件中,要根据用户使用情况修改的部分,当然,你也可以在每个任务开始时来设置IER,效果差不多,但必须包含空闲任务。因此,推荐使用在这里设置IER。

针对手工保存通用寄存器,函数中做了相应的处理,这个没什么好说的。

对于中断的说明:

如果你的系统使用的中断程序中,不需要任务切换,不使用uCOS的系统服务,你可以使用“interrupt”关键字来声明一个中断,并且是C代码的。要注意的是,在这种中断中,中断必须是关闭的,不能开中断。

如果你的中断程序中,需要任务切换或uCOS的系统服务,那么你的中断只能用汇编代码,但可以在汇编中调用C代码,这里要注意的是,此时C代码不能用“interrupt”来申明。这里附加一个中断汇编程序“EVA_T1PINT_ISR.src”,你可以进行参考。

.global _EVA_T1PINT_ISR

_EVA_T1PINT_ISR:

.ref _EVA_T1PINT_ISR_C

.ref _OSIntNesting

.ref _OSIntExit

.ref _PieCtrl

.ref _EvaRegs

PUSH RPC

PUSH AR1H:AR0H

PUSH XAR2

PUSH XAR3

PUSH XAR4

PUSH XAR5

PUSH XAR6

PUSH XAR7

PUSH XT

ASP

PUSH DP:ST1

CLRC PAGE0,OVM

CLRC AMODE

MOVW DP, #_PieCtrl+1

OR @_PieCtrl+1, #0x0002

MOVW DP, #_EvaRegs+47

OR @_EvaRegs+47, #0x0080

MOVW DP,#_OSIntNesting ;提示uc/OS-II 进入中断

INC @_OSIntNesting ; |168|

LCR _EVA_T1PINT_ISR_C

LCR _OSIntExit

POP DP:ST1

NASP

POP XT

POP XAR7

POP XAR6

POP XAR5

POP XAR4

POP XAR3

POP XAR2

POP AR1H:AR0H

POP RPC

IRET

说明:

MOVW DP, #_PieCtrl+1

OR @_PieCtrl+1, #0x0002

MOVW DP, #_EvaRegs+47

OR @_EvaRegs+47, #0x0080

是汇编中清ACK及其他位的操作。这个可以放到C代码中,全凭个人喜好。

CLRC PAGE0,OVM

CLRC AMODE

这个是一般的中断中都会有的,加和不加好像没什么不同,保险起见,还是加上了。

LCR _EVA_T1PINT_ISR_C

调用C代码,你只需要申明void EVA_T1PINT_ISR_C(void)这个函数就可以了,这个函数不能用“interrupt”来申明。这里面你可以开中断,也可以不开,全凭需要。

关于任务开关中断的说明:

由于IER是在任务切换的时候被保存到任务堆栈,因此任务开关中断不能用管IER位的方式来解决,而必须去关闭相应的外设的中断允许位来操作。好在2812中每个实用的中断都有对应的中断允许位,因而不需要去设置IER。

看门狗的使用:

多任务中,看门狗如何使用,现在还没想到好主意,只好使用了一个专门的任务来做看门狗。

0
回复
add222
LV.4
4
2014-01-15 16:09
@add222
uCOS2.00在TMS320F2812上的移植完整攻略*stk++=0x2003;/*IER=0xBBBB*/*stk++=0x2003;/*DBGSTAT=0xAAAA*/这个也很重要,是中断允许位IER。原来是设置的0xFFFF,即任务开始时,所有的中断允许开着的,这必将和你的设想不一样。因此这个应该根据你的系统使用的中断的多少来自己确定,这个也是整个C文件中,要根据用户使用情况修改的部分,当然,你也可以在每个任务开始时来设置IER,效果差不多,但必须包含空闲任务。因此,推荐使用在这里设置IER。针对手工保存通用寄存器,函数中做了相应的处理,这个没什么好说的。对于中断的说明:如果你的系统使用的中断程序中,不需要任务切换,不使用uCOS的系统服务,你可以使用“interrupt”关键字来声明一个中断,并且是C代码的。要注意的是,在这种中断中,中断必须是关闭的,不能开中断。如果你的中断程序中,需要任务切换或uCOS的系统服务,那么你的中断只能用汇编代码,但可以在汇编中调用C代码,这里要注意的是,此时C代码不能用“interrupt”来申明。这里附加一个中断汇编程序“EVA_T1PINT_ISR.src”,你可以进行参考。.global_EVA_T1PINT_ISR_EVA_T1PINT_ISR:.ref_EVA_T1PINT_ISR_C.ref_OSIntNesting.ref_OSIntExit.ref_PieCtrl.ref_EvaRegsPUSHRPCPUSHAR1H:AR0HPUSHXAR2PUSHXAR3PUSHXAR4PUSHXAR5PUSHXAR6PUSHXAR7PUSHXTASPPUSHDP:ST1CLRCPAGE0,OVMCLRCAMODEMOVWDP,#_PieCtrl+1OR@_PieCtrl+1,#0x0002MOVWDP,#_EvaRegs+47OR@_EvaRegs+47,#0x0080MOVWDP,#_OSIntNesting;提示uc/OS-II进入中断INC@_OSIntNesting;|168|LCR_EVA_T1PINT_ISR_CLCR_OSIntExitPOPDP:ST1NASPPOPXTPOPXAR7POPXAR6POPXAR5POPXAR4POPXAR3POPXAR2POPAR1H:AR0HPOPRPCIRET说明:MOVWDP,#_PieCtrl+1OR@_PieCtrl+1,#0x0002MOVWDP,#_EvaRegs+47OR@_EvaRegs+47,#0x0080是汇编中清ACK及其他位的操作。这个可以放到C代码中,全凭个人喜好。CLRCPAGE0,OVMCLRCAMODE这个是一般的中断中都会有的,加和不加好像没什么不同,保险起见,还是加上了。LCR_EVA_T1PINT_ISR_C调用C代码,你只需要申明voidEVA_T1PINT_ISR_C(void)这个函数就可以了,这个函数不能用“interrupt”来申明。这里面你可以开中断,也可以不开,全凭需要。关于任务开关中断的说明:由于IER是在任务切换的时候被保存到任务堆栈,因此任务开关中断不能用管IER位的方式来解决,而必须去关闭相应的外设的中断允许位来操作。好在2812中每个实用的中断都有对应的中断允许位,因而不需要去设置IER。看门狗的使用:多任务中,看门狗如何使用,现在还没想到好主意,只好使用了一个专门的任务来做看门狗。
0
回复
2017-04-01 17:55
@add222
uCOS2.00在TMS320F2812上的移植完整攻略.rar

厉害!最近也在往28035系列上移植,参考下你的例程,谢谢了!

0
回复