STC 原生RTOS PK 移植RTOS
本帖最后由 CosyOS 于 2023-12-29 11:45 编辑STC 原生RTOS PK 移植RTOS
一、移植RTOS可能涉及到的一些问题
1、任务切换
不同内核的MCU,在任务切换时,出入栈的方法可能有所不同,需做相关调整。
2、临界区保护
不同内核的MCU,开关中断的方法可能有所不同,需做相关调整。
3、系统全局变量访问
8051:只有单字节变量访问不会重入;
80251:data、edata直接寻址(1~4字节)不会重入,间接寻址(1~2字节)不会重入;
Arm32:所有(1~4字节)访问不会重入;
如果一个原生仅支持Arm32或更高端内核的RTOS,移植到51或251,所有系统全局变量都要
考虑是否有重入的可能(因为RTOS的作者从来不会考虑这个问题,因为根本不需要)。
4、系统服务函数可重入
很多RTOS中的系统服务函数,是需要可重入的,典型的示例如下(以任务中调用服务为例):
RET_t Function(p1, p2, ..., pn)
{
lv1; lv2; ... lvn; // 定义局部变量
... ...;
进入任务临界区;
临界区保护代码;
退出任务临界区;
... ...;
}
如果这样的RTOS移植到251,还非常好处理,只需要一定大小的edata,并生成全局可重入函数即可解决。
可如果移植到51,将变得非常艰难。
1、仔细检查每个服务函数是否已经是可重入函数(形参和局部变量都是寄存器变量),然而这又取决于多方面因素,还与编译器优化等级有关(keil c51 4级优化以上才支持寄存器变量),是无常的,所以根本无法采用。
2、每个服务函数的声明和定义都加上“reentrant”属性,再增加XBP入出任务栈,虽然可以实现,但性能将会大打折扣,使本来就弱的51更加雪上加霜。
二、CosyOS对相关问题的处理
由于CosyOS是原生支持STC 8051和32位8051的,在设计之初就考虑到了上述问题,并采取了一系列行之有效的措施,不但解决了问题,还可实现高性能。
下面主要介绍一下CosyOS对系统服务可重入的处理(以任务中调用服务为例):
1、本地代码
do{ \
进入任务临界区; \
本地执行服务; \
退出任务临界区; \
}while(false)
由于是本地独立的代码,并非调用函数,所以不存在重入的问题。
2、调用服务函数(无返回值)
do{ \
进入任务临界区; \
调用服务函数(); \
}while(false)
由于是在进入任务临界区之后才调用的服务函数,所以服务函数是不会重入的,也不需要可重入。
服务函数在返回时会自动退出任务临界区。
3、调用服务函数(有返回值)
( \
__enter_critical() ? 调用服务函数() : 返回一个其它值 \
)
采用了三目运算,巧妙的实现了在进入任务临界区之后再调用服务函数并返回值。
__enter_critical()的返回值为真,必然会调用服务函数并返回值;为假时返回一个其它值是在欺骗编译器,这种情况永远不会发生。
这一类服务又可细分为三类:
1、服务函数在退出任务临界区后返回常量或寄存器变量或当前任务节点中的变量,这一类服务函数,在退出任务临界区之前是不会重入的,在退出之后是可重入的。
2、服务函数会中途退出任务临界区并触发任务调度,当再次回到当前位置时,会直接返回任务节点中的变量,这一类服务函数,与上一类相同。
3、服务函数会中途退出任务临界区并触发任务调度,当再次回到当前位置时,会再次访问形参或局部变量,而后返回,这一类服务函数需额外定义为可重入函数。
CosyOS需额外定义为可重入函数的系统服务(已加入了reentrant属性):
1、任务中接收私信,uRecvDM(tc);
2、任务中接收邮件,uRecvMail(mail, mbox, tc);
3、中断中接收邮件,iRecvMail(mail, mbox);
4、中断中接收消息,iRecvMsg(que);
对于用户来说:
1、如果是8051内核、80251内核(keil C251 Version 1.x),如果用户调用了上述的四个服务,需要用户自行在启动文件中配置可重入栈。
2、Arm内核、80251内核(keil C251 Version 2或更高版本),用户无需理会。
但有一点需要注意:
对于80251内核(keil C251 Version 2或更高版本),您的自定义函数如需可重入,可使用reentrant属性声明,
但不要勾选编译器的 Generate reentrant functions 选项,原因是CosyOS内核为实现高效大量声明或定义了局部的bit型变量,将与此选项冲突。
可见,CosyOS所用的方法可以说是各种内核通吃,尽可能的摆脱了系统服务对可重入栈的依赖,即使是8051也可轻松实现高性能。
计划在下一版本中把任务中接收私信、任务中接收邮件调整为不使用可重入栈;
针对51,中断中接收邮件、中断中接收消息调整为限制调用(只允许在相同优先级的各个中断中调用),用户的自定义函数也不允许使用可重入栈,使51彻底摆脱可重入栈,全面提速。
本帖最后由 杨为民 于 2023-5-18 09:44 编辑
(1)支持作者给出系统的设计说明。世上之事没有万全之道,只有各种权衡和选择。就像高级厨师亲自解锁作品创意,不仅能够使食客了解其作品,也有助于食客提升自己的饮食文化水平。
(2)支持本文的PK方法。只有对比,方知高下;只有对比,才能选择。对于用户的具体项目,没有最好的RTOS,只有最合适的RTOS。
(3)建议作者对于自己的每一个特色之处,给出一个最简单的范例(比如只使用LED灯,这样在打狗棒和降龙棍上也可以学习)。这样不但可以方便STC单片机的入门者进行学习理解,整体提升STC单片机用户的RTOS编程水平,而且可以让STC单片机这匹宝马配上RTOS这座金鞍提供给广大的STC单片机用户。
(1)PK,在中国古代叫打擂台。古代文人打擂台,通常是对对联。你出一上联,我对一下联,然后请泰斗或者大众进行评判,三打两胜。我正在论坛里移植uC/OS-II到STC8H单片机上,所以我自觉接受PK。正如你在前面临界区讨论中说的“真理越辩越明”。胜负不是目的,提高选手和观众的水平是目的。
(2)楼主是擂主,我已经看到你的范例,涵盖了STC单片机上的所有中断,如果是上联,那也是云南昆明大观楼的180字长联的上联。我自认用现在的uC/OS-II没有办法写出类似的RTOS程序,第一局我认输,1:0。
(3)第2局轮我出题。我在前面的论坛帖子给出了个只用LED灯的RTOS测试程序,并给出了程序介绍,楼主是否也能给出对应的CosyOS的程序,以便我们学习了解CosyOS原生RTOS系统?
决战紫禁之巅!两大绝世高手的巅峰对话!振奋人心,前排观战! 厉害{:4_250:} 小板凳已经做好啦{:4_174:}{:4_174:}{:4_174:} 端好小板凳,观战{:4_200:} 本帖最后由 CosyOS 于 2023-5-18 13:34 编辑
杨为民 发表于 2023-5-18 10:17
(1)PK,在中国古代叫打擂台。古代文人打擂台,通常是对对联。你出一上联,我对一下联,然后请泰斗或者大 ...
“PK”这个词可能我用的不好,应该说是比较或对比,是原生RTOS与移植RTOS的对比。对比的目的也不是分个高下,而是阐明各自的技术特点,在此过程中,使广大的STC爱好者能够对RTOS有个更加深入的了解。
杨老师是真正的RTOS专家,能够移植各大RTOS,足见在RTOS方面的造诣精深。
以后还请杨老师不吝赐教,多多指出CosyOS的不足之处,使CosyOS能够不断完善。
这个“LED灯的测试程序”待我抽空看下怎么回事。。。
"3、系统全局变量访问
8051:只有单字节变量访问不会重入;
80251:data、edata直接寻址(1~4字节)不会重入,间接寻址(1~2字节)不会重入;
Arm32:所有(1~4字节)访问不会重入;
如果一个原生仅支持Arm32或更高端内核的RTOS,移植到51或251,所有系统全局变量都要
考虑是否有重入的可能(因为RTOS的作者从来不会考虑这个问题,因为根本不需要)。"
楼主提出了一个全局变量重入的问题/概念,笔者确实没有听说过(只研究过函数重入问题),楼主是否能举例介绍一下是什么意思?根据你上面括号里的话,我猜测这个问题只是CosyOS这个系统独有的问题,会不会是CosyOS的软肋呢?
本帖最后由 CosyOS 于 2023-5-18 14:51 编辑
杨为民 发表于 2023-5-18 13:46
"3、系统全局变量访问
8051:只有单字节变量访问不会重入;
80251:data、edata直接寻址(1~4字节)不会重 ...
首先,CosyOS当然不会存在这个问题。
其它的RTOS是否存在这样的问题我也不能确定,我没有时间仔细研究其它RTOS的源码,只是在理论中分析有这个可能。
我举个可能的例子:
RET_t Function(p1, p2, ..., pn)
{
lv1; lv2; ... lvn; // 定义局部变量
... ...;
访问系统全局变量gv1;
... ...;
进入任务临界区;
临界区保护代码;
退出任务临界区;
... ...;
}
比如gv1有4个字节,“gv1”与“临界区保护代码”又不存在关联性,不需要原子操作(可以被打断),这样,RTOS作者可能没有把gv1的访问放到临界区里,因为gv1是不会重入的(Arm汇编单指令完成访问)。
可移植到251就不一定了,要看具体情况;移植到51就一定会发生重入。
或者是这样:
void Function(void)
{
... ...;
访问系统全局变量gv1;
... ...;
}
访问gv1没有加临界区保护,Arm32当然不需要,可251、51就要出问题了。