CosyOS 发表于 2023-5-31 17:42:39

STC单片机 - 数据覆盖(OVERLAY)对RTOS的影响

本帖最后由 CosyOS 于 2023-5-31 18:29 编辑

STC单片机 - 数据覆盖(OVERLAY)对RTOS的影响

Keil C51/C251,默认会启用数据覆盖(OVERLAY)技术,以调用树为基本依据,实现各函数局部变量的内存空间复用,以节约内存。

如果是裸机编程,这无疑是好的措施,可显著的减少内存空间的占用,节约内存。
然而,对于RTOS来说,这将成为RTOS的噩梦!!!
原因是keil并不知道你使用了RTOS(keil自家的除外),更不知道你的各个任务是任务(像中断一样具有动态特性),
以此将生成错误的调用树,导致数据覆盖算法出错。
如下方示例(使用了CosyOS,并启用了数据覆盖):




现有的调用树
各中断都是独立的树(NEW ROOT),包括UART1_ISR、UART2_ISR、UART3_ISR、UART4_ISR,I2C_ISR,SYSTICK_HANDLER,TASK_SCHEDULER。
?C_C51STARTUP也为独立的树,并调用了MAIN和?C_INITSEG。
?C_INITSEG调用了各个任务(UART2_SEND_TASK等)和“定时查询事件函数”(FTIMQRY_EVENT_0等)。

应重新调整的调用树
首先,各任务应像中断一样,也应生成独立的调用树(NEW ROOT),才是正确的。
其次,“定时查询事件函数”是在系统滴答中断中通过函数指针来调用的,所以应在SYSTICK_HANDLER中调用。
有关函数指针会导致相关调用树和数据覆盖算法出错的问题,即使是裸机编程也一样存在,这点尤为需要注意!


解决办法

1、修改调用树,并使调用关系正确
   然而这又是多么繁复的工作,而且需要用户自己来完成,对于RTOS来说,此法当然是行不通的。

2、所有任务和被任务调用的函数,局部变量一律定义为“static”
   这个方法看似能解决问题,但又要对用户提出要求,而且会造成本来可以成为寄存器变量的局部变量,也只能是内存变量。
   函数指针的问题仍然得不到解决。所以,此法也不可取。

3、LX51/251 Misc controls 添加控制命令“NOOVERLAY”
   此法可完美的解决覆盖问题,缺点是“NOOVERLAY”会导致控制命令“REMOVEUNUSED”失效,用户只能自己手动删除未使用的C文件或库函数。

4、reentrant && REMOVEUNUSED || Generate reentrant funcitons && REMOVEUNUSED
   对于51来说,所有任务和被任务调用的函数声明为可重入函数(reentrant),并添加控制命令“REMOVEUNUSED”。
   对于251来说,生成全局可重入函数(Generate reentrant funcitons),并添加控制命令“REMOVEUNUSED”。

可见,方法3和方法4都是实用的方法,在于用户自己的选择。


STC32 - 方法3 & 方法4

方法3的缺点
1、需要用户自己手动移除未使用的代码段和数据段。
2、需要可重入的函数也只能单独声明为reentrant。

方法4的优点
1、所有函数都可成为可重入函数,用户可不必考虑哪些函数需要可重入,也不用给需要可重入的自定义函数声明为reentrant。
2、“REMOVEUNUSED”可自动移除未使用的代码段和数据段,可谓是方便至极。

方法4的缺点
1、需要更大的edata内存(原因是可重入栈只能在edata中),任务栈也要加大。
2、所有函数中不能定义局部的bit型变量,也不能声明。
3、可重入栈中的局部变量都是通过DR60间接寻址,所以方法4在速度上会稍慢于方法3。

可见,方法3在节约edata内存和性能方面更具优势,方法4则具有更高的易用性。
总之,方法3和方法4都是实用的方法,用户可权衡多方面因素后选择。



神农鼎 发表于 2023-5-31 18:04:57

学习

LAOXU 发表于 2023-9-22 11:54:30

学习了
页: [1]
查看完整版本: STC单片机 - 数据覆盖(OVERLAY)对RTOS的影响