最新版本uC-OS2-2.93.01已移植到STC32G上,请帮忙查错
uCOS-II-2.93.01 for STC32G12K128 请帮忙查错本移植参考STC论坛网友tzz1983的移植方案,使用定时器4模拟软件中断PendSv
一,使用注意:
本移植整个工程统一使用寄存器组0,用户不能修改寄存器组。寄存器组1,2,3共24字节用于data/edata区。
中断函数执行完毕,执行RETI返回前不建议关闭中断总开关。如果关闭一般认为是程序员的Bug。
系统启动前不能开中断,不然OSIntNesting一直会++。
二,void OSStartHighRdy(void)行数提供了3种方法切换到第一个任务。
<font size="3">//方法1:使用ERET返回,返回前需要从新调整堆栈的内容,由于任务第一次运行,R4,R5,R6 给任何值都没关系。
//读取任务的SP
__asm { MOV DR4,OSTCBCur }
__asm { MOV WR2,@WR6+0x2 }
__asm { MOV DR60,DR0 }
//寄存器出栈
__asm { POP PSW }
__asm { POP DR0 }
__asm { POP DR4 }
__asm { POP DR8 }
__asm { POP DR12 }
__asm { POP DR16 }
__asm { POP DR20 }
__asm { POP DR24 }
__asm { POP DR28 }
__asm { POP DR56 }
//PC和PSW1出栈
__asm { POP R4 }
__asm { POP R6 }
__asm { POP R5 }
__asm { POP PSW1 }
//把返回地址格式做成ERET的返回格试
__asm { PUSHR5 }
__asm { PUSHR4 }
__asm { PUSHR6 }
__asm { SETBEA }
//用ERET指令转移到任务中去, 0XAA是ERET指令的编码
__asm { DB 0AAH }
//方法2:使用RETI返回,由于系统刚开始,其他中断都没有开始触发。用RETI完全没问题的。
//读取任务的SP
__asm { MOV DR4,OSTCBCur }
__asm { MOV WR2,@WR6+0x2 }
__asm { MOV DR60,DR0 }
//寄存器出栈
__asm { POP PSW }
__asm { POP DR0 }
__asm { POP DR4 }
__asm { POP DR8 }
__asm { POP DR12 }
__asm { POP DR16 }
__asm { POP DR20 }
__asm { POP DR24 }
__asm { POP DR28 }
__asm { POP DR56 }
__asm { SETBEA }
__asm { RETI }
//方法3:使用PendSvIsr中断切换到第一个任务
//巧妙指向DR0内存位置。SP保存到任务控制块的时候,实际操作是MOV DR0,DR0,也就是DR0值不变
OSTCBCur = (OS_TCB *)0;
PendSv_GenerateSWInterrupt();
EA = 1;
while(1);</font>
三,优化了OS_CPU_PendSVHandler中断函数
<font size="3">void OS_CPU_PendSVHandler( void )
{
//函数入口标号,中断跳转到入口标号,解决huge和large存储模式不一样函数名字不一样的问题。
__asm {OS_CPU_PendSVHandler_00:}
//寄存器入栈
__asm { PUSHDR56 }
__asm { PUSHDR28 }
__asm { PUSHDR24 }
__asm { PUSHDR20 }
__asm { PUSHDR16 }
__asm { PUSHDR12 }
__asm { PUSHDR8 }
__asm { PUSHDR4 }
__asm { PUSHDR0 }
__asm { PUSHPSW }
//SP保存到任务控制块
__asm { MOV DR0,DR60 }
__asm { MOV DR4,OSTCBCur }
__asm { MOV @WR6+0x2,WR2 }
//保存并关EA,其实EA=0问题也不大,如果中断返回的时候EA=0,这个很明显是程序员的bug
__asm { SETBC }
__asm { JBC EA,PendSvIsr_01}
__asm { CLR C }
__asm { PendSvIsr_01: }
__asm { PUSHPSW }
OSTaskSwHook();
OSPrioCur = OSPrioHighRdy;
OSTCBCur= OSTCBHighRdy;
//恢复EA
__asm{POP PSW }
__asm{ MOV EA,C }
//读取任务的SP
// ;OSTCBCur= OSTCBHighRdy; 的汇编
// MOV DR4,OSTCBHighRdy
// MOV OSTCBCur,DR4
//说明DR4的值已经是OSTCBCur,下面这条可以屏蔽
// __asm { MOV DR4,OSTCBCur }
__asm { MOV WR2,@WR6+0x2 }
__asm { MOV DR60,DR0 }
//寄存器出栈
__asm { POP PSW }
__asm { POP DR0 }
__asm { POP DR4 }
__asm { POP DR8 }
__asm { POP DR12 }
__asm { POP DR16 }
__asm { POP DR20 }
__asm { POP DR24 }
__asm { POP DR28 }
__asm { POP DR56 }
//中断返回
__asm { RETI }
}</font>
四,函数入口标号,中断跳转到入口标号,解决huge和large存储模式不同,函数名字不一样的问题。
/*-----------------------------------------------------------*
PendSv 向量入口引导
*-----------------------------------------------------------*/
__asm {OS_CPU_PendSVHandler_00:}
__asm { CSEG ATPendSv_EntryAddress}
__asm { JMP OS_CPU_PendSVHandler_00}
附件是最新版本的源码:
需要设置全局可重入。昨天最后整理新建了工程,忘记设置了。
熊哥威武! 真是行家一出手,就知有没有!
那个第一次切换任务用中断的方法, 有些烧脑啊, 哈哈, 牛B的, 我在脑海里转了好几圈才转出来, 就是第一次切换没有保存上下文呗, 厉害!
给熊哥几个建议:
1: 切换任务中有三个C语句, 直接全部用汇编替换, 一是便于理解, 二是你在文中有提到, C转汇编时"说明DR4的值已经是OSTCBCur" , 但这里有个隐含的条件是, C编绎一定会这么干! (个人认为编译权并不在我们手里, 万一它以后为DR8了呢,汇合编程还是小心为上).
2: 临界段模式2中 "#define OS_EXIT_CRITICAL() do{ _pop_ (ACC);IE |= ACC;}while(0) "此处个人理解是有BUG的. 此处在将C代码文档中直接插入插入C代码, 访问ACC等同于直接访问内部寄存器A,会不会破坏原文的上下文.并且貌似251这编译也不支持 _pop_ ().
3:临界段模式4过于烦锁, 为了让读者少烧脑, 是不是可以却除
tzz1983 发表于 2023-9-18 09:06
熊哥威武! 真是行家一出手,就知有没有!
那个第一次切换任务用中断的方法, 有些烧脑啊, 哈哈, 牛B的, 我在 ...
问题1,之前想过,其实我都都弄好了,只保留钩子函数。后来想还是不要改动你太多,毕竟你的成果。
需要在前面把变量调用下才能通过编译。
if(OSPrioCur);
if(OSPrioHighRdy);
if(OSTCBCur);
if(OSTCBHighRdy);
问题2,忘记测试了,C251确实不支持_push_和_pop_,代码思路没有问题的,在STC8验证过的。251有堆栈寻址,貌似不适用
问题3,这个杨老师认为最好的方法,还是保留吧。喜欢的自己选。 熊仔 发表于 2023-9-18 09:18
问题1,之前想过,其实我都都弄好了,只保留钩子函数。后来想还是不要改动你太多,毕竟你的成果。
需要在 ...
嗯 ,是的, 我移植时也遇到不能编绎, 用一个无效语句来调用一下, 后来想想直接C不影响结果, 就直接用C了, 但现在你用到了DR4.
另外138警告去处理一下, 这个更改只是为了迎和编绎器, 不算是对原代码的冒犯, 程序员肯定不喜欢warning, 屏蔽太多又不好, 不屏蔽又影响心情
1,138警告,早上的更新的已经去掉了。
2,屏蔽方法2
3,void OS_CPU_PendSVHandler( void )除了OSTaskSwHook();其他使用汇编汇编
void OS_CPU_PendSVHandler( void )
{
//下面这样做为了能使用汇编访问变量
if(OSPrioCur);
if(OSPrioHighRdy);
if(OSTCBCur);
if(OSTCBHighRdy);
//函数入口标号,中断跳转到入口标号,解决huge和large存储模式不一样函数名字不一样的问题。
__asm{
OS_CPU_PendSVHandler_00:
//寄存器入栈
PUSHDR56
PUSHDR28
PUSHDR24
PUSHDR20
PUSHDR16
PUSHDR12
PUSHDR8
PUSHDR4
PUSHDR0
PUSHPSW
//SP保存到任务控制块
MOV DR0,DR60
MOV DR4,OSTCBCur
MOV @WR6+0x2,WR2
//保存并关EA,其实EA=0问题也不大,如果中断返回的时候EA=0,这个很明显是程序员的bug
SETBC
JBC EA,PendSvIsr_01
CLR C
PendSvIsr_01:
PUSHPSW
}
//这条用C方式就是解决huge和large存储模式不一样函数名字不一样的问题
OSTaskSwHook();
__asm{
//OSPrioCur = OSPrioHighRdy;
MOV OSPrioCur,OSPrioHighRdy;使用data加速
//OSTCBCur= OSTCBHighRdy;
MOV DR4,OSTCBHighRdy
MOV OSTCBCur,DR4
//恢复EA
POP PSW
MOV EA,C
//读取任务的SP
//DR4的值已经是OSTCBCur,下面这条可以屏蔽
// MOV DR4,OSTCBCur
MOV WR2,@WR6+0x2
MOV DR60,DR0
//寄存器出栈
POP PSW
POP DR0
POP DR4
POP DR8
POP DR12
POP DR16
POP DR20
POP DR24
POP DR28
POP DR56
//中断返回
RETI
}
}
源码先不更新。
祝贺熊仔推出STC32G的移植版,这样“uCOSII-STC32G”、“C251-UCOSII”和“CosyOS”都采用了软中断作为任务切换的方法,可以互相借鉴和交流了
下面只等FreeRTOS软中断的移植版了,各位大侠加油!!
本帖最后由 CosyOS 于 2023-9-18 12:26 编辑
CosyOS允许用户自由选择一个未使用的硬件中断,来做为软中断使用。
由于CosyOS在进入任务临界区时是需要关闭系统滴答中断和这个“软中断”的,所以还需用户配置这个“软中断”的开启和关闭。
*修改版本: V1.01
*修改时间: 2023-09-18
修改:
1.临界区保护方法2屏蔽
2.void OS_CPU_PendSVHandler( void )除了OSTaskSwHook();其他使用汇编汇编
3.解决void OSStartHighRdy(void) 函数里面的方法3,OSTaskSwHook();运行2次问题。
4.增加putchar.c文件,char putchar(char c)重映射函数不能在全局可重入下使用。文件需要单独设置,才支持支持printf
CosyOS 发表于 2023-9-18 12:16
CosyOS允许用户自由选择一个未使用的硬件中断,来做为软中断使用。
最好选择能自动清零的中断。当然手动也行,多执行一条清零语句。
你的os代码太庞大了。之前看了一下,没理清,没坚持下去。以后有时间再拜读一下。