找回密码
 立即注册
查看: 961|回复: 6

STC单片机uC/OS-II移植记(8):再论STC单片机RTOS中的临界区保护方法

[复制链接]

该用户从未签到

61

主题

626

回帖

1万

积分

荣誉版主

积分
10830
发表于 2023-5-6 23:01:25 | 显示全部楼层 |阅读模式
本帖最后由 杨为民 于 2024-3-1 19:25 编辑

由于STC单片机硬件上有丰富的片上设备和中断资源,STC单片机上的RTOS的应用领域也将非常广。临界区保护是RTOS系统中的一个重要组成部分,但是采用哪种方法或者说提供哪些可选择的方法,对于不同的设计者有不同的考虑。
本文通过对STC单片机上现有的一些RTOS的临界区保护的讨论,进一步展示各种临界区保护方法的特点和适用领域。
一、CosyOS-RTOS的临界区保护方法
(1)临界区保护是单片机RTOS程序设计中的重要问题,通常在uC/OS-II、uC/OS-III和RT-Thread等RTOS中都采用了简单粗暴却也行之有效的方法:进入临界区保护时“关闭总中断”(EA=0),退出临界区保护时“打开总中断”(EA=1)。
(2)但是中断程序是单片机程序的最重要组成部分,在不正确的时机关闭和打开总中断,就影响了或者屏蔽了所有的中断,有可能对单片机整个系统产生影响,比如用定时器中断产生的1MHz的信号发生器,或者是依赖中断的高速PWM程序。这与临界区保护就形成了“鱼与熊掌”不可兼得的形势。
(3)临界区保护分为两种情况,一种是操作系统本身对系统自身的资源(任务表、调度过程等)的保护。另一种是对单片机公共资源和公共程序(过程)的保护,比如对一个12位的ADC,一个任务(如实验板上的NTC)读了一个字节后,任务被切换了,新任务重新进行了ADC变换,然后任务再切换回来后读到的另一个字节已经不是原来的字节了,就会产生错误。为了避免出现这类错误,就需要公共资源临界区保护。如果按照传统操作系统的临界区保护方法(队列、加锁解锁等)编程太过复杂,不得已FreeRTOS、RTT、uC/OS这些RTOS才提供了“关全局中断”(EA=0)的通用临界区保护手段。
(4)最近推出的STC单片机上运行的CosyOS-RTOS将上面两种情况分别对待,作者分别给出了解决方法:
“如果是全局变量访问,CosyOS提供的服务可确保不会重入,包括在中断中的读、写、和自运算。如果涉及到某些对硬件和寄存器的操作,如果仅是在任务中,可以用临界区的方法,仅关闭任务调度;如果是在中断中,只能用户自己实现机制保护或关闭总中断或用户中断了。然而,对于OS来说,在系统及服务层面上已经实现了全局不关中断,用户需要关闭中断是他的自由。Keil RTX4/5也是相同的道理,也会遇到这种情况。”
我觉得分别解决临界区保护这是一条正确的道路。
(5)在CosOS中,RTOS系统核心的临界区保护方法如下:
临界区定义_1.jpg
其中“uEnterCritical”是一个宏定义:
临界区定义_2.jpg
其中“__enter_critical”是一个实际的函数:
临界区定义_3.jpg
其中函数的实体是可以提供给用户选择或者自定义的宏“mEnterCritical”:
临界区定义_4.jpg
这个宏是一个后条件循环,首先执行了“mSTK_Disable”(ET0 = 0)。
(6)在这里进入临界区保护首先关闭了定时器0的中断允许位,这时定时器0中断就不会再发生了,RTOS系统也就不会再进行任务调度,这样就保护了与任务调度有关的RTOS系统的变量与过程的执行的完整性。
二、RTOS临界区保护的设计理念
临界区保护对于单片机RTOS编程肯定是必要的,但是在具体的某一个RTOS里面如何实现是一个选择,是一种设计理念。

(7)目前STC单片机的uC/OS-II版本是从PC DOS平台上运行的版本移植而来,而DOS平台本身就提供了系统核心级的保护,因此提供了三种方法供用户选择。
临界区定义_5_80x86.jpg
再移植到STC8单片机上,目前实现的为:
临界区定义_6_8051.jpg
(8)而在移植到STC32G上的FreeRTOS中,临界区保护方法从中断与非中断的角度划分为两种:
临界区定义_7_80251.jpg
第一种在非中断程序中使用的一般称为“任务级临界区保护”,第二种在中断程序中使用的一般称为“系统级临界区保护”。

在FreeRTOS中实现任务级临界区保护的方法为:
临界区定义_8_FreeRTOS.jpg
仍然是简单粗暴的开关总中断了事。
对于系统级临界区保护FreeRTOS有更深层的考虑,采用了比较复杂的方法来实现,这里就不具体介绍了。
三、RTOS临界区保护嵌套的问题
(9)临界区保护嵌套是指用户的某个程序过程需要整个地进行保护,但是这个过程包含多个系统函数,这些函数里面已经有临界区保护的进入和退出(配对的关闭和打开总中断)了,这时虽然在过程的开始进入临界区保护(关闭了总中断),但是如果临界区保护不是可以嵌套的,这时等不到整个过程结束,里面包含的函数中的退出临界区保护程序(EA=1)就会提前将总中断打开,这就违背了程序设计者的初衷,严重的可能产生可怕的后果。
(10)这种嵌套关系就像C语言里面的注释语句。大家可以看到很多RTOS程序的程序行后面都有一个“/*”与“*/”配对注释,这是C语言语法中的“行注释语句”。
如果你要把多个程序行组成的一整段程序用“/*”与“*/”对都注释掉(块注释),但其中的某几行程序包含这种行注释,那么你可以看到你编译器碰到第一个行注释的结尾“*/”就离开注释区,把其后到下一个行注释开始的“/*”的部分露出来,没有进行注释,给程序员带来很大的麻烦。这也就是提倡使用C++的行尾注释符“//”语法的原因了。

(11)对于笔者前文介绍的移植到STC8上面的“uC/OS-II”就存在这个问题,其中系统中断的程序为:
临界区定义_9_uCOSII.jpg
其中的第472行程序关闭总中断和第485行打开总中断就是想保护整个系统中断(定时器0中断)的完整执行。

为了显示这个临界区过程保护的情况,笔者在P2端口连接了一个8路逻辑分析仪来监测这个中断的高速过程。其中第1路高电平代表进入系统中断(第470行,第488行),第2路代表高电平代表总中断EA打开(第473行,第486行),同时在临界区保护的宏定义也增加相应的语句:
临界区定义_10_EA.jpg
(12)下图是逻辑分析仪监测的截屏:
临界区定义_11_嵌入.jpg
最上面第0通道是一个作为参考10KHz的定时器中断信号,第1通道是20毫秒的系统中断,第2通道是总中断EA的开关情况。
对于第0通道参考中断,每个中断中只有一个临界区保护,不存在嵌套,因此对应第0路的高电平脉冲,只有一次关开总中断的过程。
但是对于第1通道系统中断,每个中断中包含了第479行的系统时间Tick函数(内含临界区保护代码了)和第482行的系统中断任务调度函数(内含临界区保护代码了),因此在与第1通道高电平脉冲对应的过程中,第2通道显示有总中断EA有多次的开关过程,这就是临界区保护嵌套现象。
显然,这种多次的开关总中断,并不符合程序设计者的初衷。
四、结束语
因此作为一个优秀的RTOS,系统的设计者同时也应该给出临界区嵌套问题的解决方法。
(13)参考前面的PC DOS下的uC/OS-II系统的临界区保护方法选择图,第2种和第3种方法都是支持临界区保护嵌套的,作者选择了第2种,并且在其著作中阐明迫不得已用户才需选择第1种,因为它是不支持嵌套的。
(14)STC8上的uC/OS-II移植者也是希望支持临界区保护嵌套,在上面程序图中,uC/OS-II移植版的方法3忠实地将8086CPU上的方法3移植到了STC8单片机上,但是临界区嵌套保护的效果显然不理想,所以移植者写下移植体会:“很遗憾,第三种方式“屡试不爽””。
我认为效果不理想的问题出在两种CPU的中断过程不一样。8086 CPU在进入中断时把中断标志FLAG硬件方式推入了堆栈,中断退出时又硬件把这个中断标志恢复了。
无论8051或者80251的中断硬件都没有自动地将总中断标志EA推入和弹出系统堆栈,因此uC/OS-II的第3种方法很难以实现,应该在今后的移植中去除。
(15)而RT-Thread的作者认识到临界区保护嵌套使用的必要性,因此给出了一种关闭中断和允许临界区保护嵌套的特色方法,一举成名。这时后话,待将RTT移植到STC单片机后再讨论。
(16)建议:在CosyOS中,作者也可以简单地加入一个开关总中断的临界区保护方法让用户选择,既与现在的方法不冲突,又增加了RTOS的完整性:
#define OS_ENTER_CRITICAL() EA=0 /* 直接禁止中断*/

#define OS_EXIT_CRITICAL()   EA=1 /* 直接允许中断 */

回复 送花

使用道具 举报

该用户从未签到

551

主题

9291

回帖

1万

积分

管理员

积分
14057
发表于 2023-5-6 23:38:45 | 显示全部楼层
杨老师为 STC 32位8051 和 1T 8051全面进军 RTOS 指出了方向,感谢 CosyOS 大侠的贡献,继续前行
回复 支持 反对 送花

使用道具 举报

  • TA的每日心情
    奋斗
    6 小时前
  • 签到天数: 158 天

    [LV.7]常住居民III

    5

    主题

    487

    回帖

    2110

    积分

    荣誉版主

    积分
    2110
    发表于 2023-5-7 13:54:10 | 显示全部楼层
    感谢杨大侠对RTOS临界区保护问题的详细阐述,讲的非常专业、全面。
    关于CosyOS“全局不关中断”的说法我是模仿了Keil RTX,他也是这样宣传的,M3、M4内核全局不关中断,零中断延迟。
    但实际上他所说的“全局不关中断”仅是指RTX内核中没有关闭中断的操作,不代表用户没有这方面的需求。
    CosyOS也是相同的道理,在内核中也没有关闭总中断的操作,用户有需要时可以自行关闭。
    而FreeRTOS、UCOS、RTT等则完全不同,他们在很多内核服务中都有关闭总中断的操作,这与用户自己关闭总中断是不一样的。
    正如杨大侠所说,对单片机公共资源和公共程序过程的保护,有可能还是需要用户进入临界区(关闭任务调度或总中断)。



    关于临界区保护嵌套问题,也一直在考虑,只是还有一些问题没有好的解决方案,会尽快在未来的版本升级后实现。
    未来,我也会增加开关总中断进行临界区保护的API,提供给用户。
    最后,由衷的感谢杨大侠提出的建议,能让CosyOS不断完善。
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    551

    主题

    9291

    回帖

    1万

    积分

    管理员

    积分
    14057
    发表于 2023-5-7 14:22:34 | 显示全部楼层
    两位大师在 www.STCAIMCU.com 山巅的高峰对话,
    www.STCAIMCU.com 直接成为了 RTOS 的新起点,
    东风到处,即是真理

    大道已在 www.STCAIMCU.com

    STC89C52RC全面升级到32位8051,STC8051H/32位8051,
    国庆贺礼,以此纪念为8051世界做出杰出贡献的历代大贤 !

    STC8051H-45MHz-LQFP44/LQFP48/PDIP40,
    管脚兼容STC89C52/STC10/STC11/STC12 !
    自带硬件USB[D-/P3.0,D+/P3.1]下载/仿真,SWD仿真,
    18K SRAM [2K edata, 16k xdata],  64K Flash,
    DMA, 4串口, SPI/I2C, TFT, 12位ADC, 比较器,PWM, RMB2.5

    全面支援 CosyOS




    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    11

    主题

    329

    回帖

    872

    积分

    荣誉版主

    积分
    872
    发表于 2023-8-8 13:13:25 来自手机 | 显示全部楼层
    本帖最后由 熊仔 于 2023-8-8 13:27 编辑

    上周末研究了一下这个临界区保护问题。
    确实方法一问题很大,不能嵌套。
    方法二和方法三,在51单片机上能实现的.
    显然方法二的效率比较高,直接IE出入栈,没有变量的参与。
    方法三会慢很多,因为是操作xdata.
    后面我会重新整理开一个帖子.
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    4

    主题

    62

    回帖

    300

    积分

    中级会员

    积分
    300
    发表于 2023-12-29 19:11:40 | 显示全部楼层
    如果原始的中断嵌套, 中断现场的保护是硬件直接支持的
    为什么还要让OS接管硬件中断?

    点评

    (1)操作系统分两类,第一类是裸机系统,用户直接编写程序控制整个硬件系统,包括用户自己编写中断服务程序。通常从复位地址开始的程序流称为“后台程序”,把中断服务程序称为“前台任务”。这种裸机系统因此也被  详情 回复 发表于 2023-12-29 21:15
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    61

    主题

    626

    回帖

    1万

    积分

    荣誉版主

    积分
    10830
     楼主| 发表于 2023-12-29 21:15:11 | 显示全部楼层
    13918210822 发表于 2023-12-29 19:11
    如果原始的中断嵌套, 中断现场的保护是硬件直接支持的
    为什么还要让OS接管硬件中断? ...

    (1)操作系统分两类,第一类是裸机系统,用户直接编写程序控制整个硬件系统,包括用户自己编写中断服务程序。通常从复位地址开始的程序流称为“后台程序”,把中断服务程序称为“前台任务”。这种裸机系统因此也被称为“前后台操作系统”,由于中断服务程序是用户自己编写的,所以其实时响应能力是OS中最高的,是一种标准的RTOS。

    (2)第二类是DOS系统,就是常见的MS-DOS,Windows等。由于硬件中断存在屏蔽问题,高优先级中断不退出,低优先级的中断就会被阻塞不能发生,如果被阻塞的是像串口和和网络这样的异步通讯,那么就会产生丢失数据等一系列问题。因此对于DOS系统,操作系统必须接管所有的中断,用户只能通过驱动程序和钩子函数(回调函数)等方法处理自己的中断,避免程序错误产生系统崩溃。因此OS都必须接管硬件中断。
    (3)单片机的RTOS本质上是最简单的DOS,因此同样存在中断阻塞和系统崩溃的问题,单片机上的RTOS有很多种类,其中的一些接管全部硬件中断,另一些完全不接管硬件中断,而主流的单片机RTOS提供选项让用户决定系统和用户各管理哪些硬件中断。因此单片机RTOS并不统一是哪一种,用户可以根据需要选择。同样单片机RTOS的研制者也可以自由选择如何接管中断,只是应该如实告诉用户,方便用户选择使用,避免造成严重后果。
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-2 16:17 , Processed in 0.075766 second(s), 57 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表