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

关于STC单片机RTOS中的临界区保护方法的研究

[复制链接]

该用户从未签到

11

主题

331

回帖

886

积分

荣誉版主

积分
886
发表于 2023-8-8 20:21:01 | 显示全部楼层 |阅读模式
本帖最后由 熊仔 于 2023-8-8 23:27 编辑

目前看到移植到STC单片机的RTOS例子,对临界区保护基本都是简单粗暴的开关中断。


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


通过查看uCOSII移植到其他cpu的os_cpu.h文件。里面有规定单片机临界区的3种方法
方法1:简单开关中断
方法2:利用硬件栈保存中断状态,再关中断,退出临界区的时候弹出栈。
方法3:通过本地变量“cpu_sr”保存中断状态,然后禁用中断,退出临界区的时候,将“cpu_sr”写入到中断状态寄存器。

方法2和方法3都是通过保留中断状态来禁用/启用中断,这样设计临界区就可以嵌套。

对于目前移植到STC51单片机的uCOSII例子。添加方法2和方法3
  1. #if OS_CRITICAL_METHOD==2
  2. #include <intrins.h>
  3. #define OS_ENTER_CRITICAL()do{_push_(IE);EA = 0;}while(0)   /* 利用堆栈保存中断状态,再关中断  */
  4. #define OS_EXIT_CRITICAL()do{ _pop_ (IE);}while(0)          /* 将IE从堆栈弹出,恢复IE值    */
  5. #endif
  6. #if OS_CRITICAL_METHOD==3
  7. #define OS_ENTER_CRITICAL() do{ cpu_sr=IE;EA = 0;}while(0)
  8. #define OS_EXIT_CRITICAL()  do{ IE = cpu_sr; }while(0)
  9. #endif
复制代码
修改宏定义#define OS_CRITICAL_METHOD  2 或者#define OS_CRITICAL_METHOD  3
这个时候编译运行,系统运行不正确的。

对方法2,通过调试发现中断切换任务调用OSIntExit()函数,然后OS_ENTER_CRITICAL();最后通过OSIntCtxSw();切换任务,这里没有调用OS_EXIT_CRITICAL();导致出问题。
问题分析:OS_ENTER_CRITICAL()时导致中断切换任务的时候硬件堆栈多入了一个_push_(IE),
解决方法:OSIntCtxSw()函数调整SP的时候应该多减1,原来SP=SP-4改为SP=SP-5
修改代码如下:
  1. IF OS_CRITICAL_METHOD == 2
  2.         ;调整SP指针去掉在调用OSIntExit()、OSIntCtxSw()、OS_ENTER_CRITICAL()过程中压入堆栈的多余内容
  3.         ;SP=SP-5
  4.         MOV  A,SP
  5.         CLR  C
  6.         SUBB A,#5
  7.         MOV  SP,A
  8. ENDIF
复制代码


对方法3,通过调试也是中断切换任务调用OSIntExit()函数,然后OS_ENTER_CRITICAL();最后通过OSIntCtxSw();切换任务,这里没有调用OS_EXIT_CRITICAL();导致出问题。


//问题分析:可重入函数的局部变量cpu_sr会入仿真栈。导致中断切换任务的时候,仿真堆栈出问题。
//解决方法:OSIntCtxSw()函数执行时需要对仿真堆栈指针++操作。

  1. IF OS_CRITICAL_METHOD == 3
  2.         ;调整OS_ENTER_CRITICAL()过程中cpu_sr压入仿真栈的内容,?C_XBP++操作
  3.         INC     (?C_XBP+1)
  4.         MOV     A,(?C_XBP+1)
  5.         JNZ     C_XBPADD_END
  6.         INC     ?C_XBP
  7. C_XBPADD_END:
  8.         ;调整SP指针去掉在调用OSIntExit()、OSIntCtxSw()过程中压入堆栈的多余内容
  9.         ;SP=SP-4
  10.         MOV  A,SP
  11.         CLR  C
  12.         SUBB A,#4
  13.         MOV  SP,A
  14. ENDIF  
复制代码

为了方便条件编译,在os_cpu_a.A51文件的开头定义一个常量 OS_CRITICAL_METHOD
  1. $NOMOD51
  2.    
  3. ;注意OS_CPU.H文件也需要设置下OS_CRITICAL_METHOD 选哪种一种方法 ,需要保持两边一致。
  4. OS_CRITICAL_METHOD      EQU     2     
复制代码


OSIntCtxSw开头部分的代码修改:
  1. OSIntCtxSw:
  2.         USING 0
  3. IF OS_CRITICAL_METHOD == 1
  4.         ;调整SP指针去掉在调用OSIntExit()、OSIntCtxSw()过程中压入堆栈的多余内容
  5.         ;SP=SP-4
  6.         MOV  A,SP
  7.         CLR  C
  8.         SUBB A,#4
  9.         MOV  SP,A
  10. ENDIF
  11.    
  12. IF OS_CRITICAL_METHOD == 2
  13.         ;调整SP指针去掉在调用OSIntExit()、OSIntCtxSw()、OS_ENTER_CRITICAL()过程中压入堆栈的多余内容
  14.         ;SP=SP-5
  15.         MOV  A,SP
  16.         CLR  C
  17.         SUBB A,#5
  18.         MOV  SP,A
  19. ENDIF
  20.    
  21. IF OS_CRITICAL_METHOD == 3
  22.         ;调整OS_ENTER_CRITICAL()过程中cpu_sr压入仿真栈的内容,?C_XBP++操作
  23.         INC     (?C_XBP+1)
  24.         MOV     A,(?C_XBP+1)
  25.         JNZ     C_XBPADD_END
  26.         INC     ?C_XBP
  27. C_XBPADD_END:
  28.         ;调整SP指针去掉在调用OSIntExit()、OSIntCtxSw()过程中压入堆栈的多余内容
  29.         ;SP=SP-4
  30.         MOV  A,SP
  31.         CLR  C
  32.         SUBB A,#4
  33.         MOV  SP,A
  34. ENDIF  
复制代码


这样,STC的51单片机就能使用方法2和方法3进行临界区的保护。解决嵌套问题。
显然方法2的效率比较高,直接IE出入栈,没有变量的参与。
方法3会慢很多,因为是操作xdata进出仿真栈。


注意:通过网上查资料,方法2使用有注意问题,当用户使用的处理器有堆栈指针相对寻址模式时,可能出现严重错误。8051没有堆栈指针相对寻址模式可以放心用。


回复 送花

使用道具 举报

该用户从未签到

551

主题

9567

回帖

1万

积分

管理员

积分
14057
发表于 2023-8-8 22:07:27 | 显示全部楼层
这是高手必须懂汇编的铁证啊 !!!
回复 支持 反对 送花

使用道具 举报

该用户从未签到

63

主题

703

回帖

1万

积分

荣誉版主

积分
10924
发表于 2023-8-8 22:40:38 | 显示全部楼层
把你修改后的程序传上来,供大家分享讨论

点评

临界区保护方法上面的代码都提供了,拷贝到到移植的工程就可以。 我已经移植到最新版本的uCOSII 2.93.01。还要再测一下,新版本新增的功能。都能工作了再放出来。  详情 回复 发表于 2023-8-9 08:27
回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

331

回帖

886

积分

荣誉版主

积分
886
 楼主| 发表于 2023-8-9 08:27:41 来自手机 | 显示全部楼层
杨为民 发表于 2023-8-8 22:40
把你修改后的程序传上来,供大家分享讨论

临界区保护方法上面的代码都提供了,拷贝到到移植的工程就可以。
我已经移植到最新版本的uCOSII 2.93.01。还要再测一下,新版本新增的功能。都能工作了再放出来。

点评

期待你的移植版本  详情 回复 发表于 2023-8-9 10:48
回复 支持 反对 送花

使用道具 举报

  • TA的每日心情
    开心
    2023-12-18 09:20
  • 签到天数: 1 天

    [LV.1]初来乍到

    12

    主题

    90

    回帖

    249

    积分

    中级会员

    积分
    249
    发表于 2023-8-9 09:54:40 | 显示全部楼层
    简单应用其实RTX51-TNIY也够用了,信号量使用和传递需要量大的话做成结构加锁就行
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2023-12-18 09:20
  • 签到天数: 1 天

    [LV.1]初来乍到

    12

    主题

    90

    回帖

    249

    积分

    中级会员

    积分
    249
    发表于 2023-8-9 09:56:13 | 显示全部楼层
    对于工程使用来说,一定需要成熟的系统,这些修改的没经过验证评估的只能作为爱好玩玩。
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    63

    主题

    703

    回帖

    1万

    积分

    荣誉版主

    积分
    10924
    发表于 2023-8-9 10:48:12 | 显示全部楼层
    熊仔 发表于 2023-8-9 08:27
    临界区保护方法上面的代码都提供了,拷贝到到移植的工程就可以。
    我已经移植到最新版本的uCOSII 2.93.01 ...

    期待你的移植版本
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-22 06:12 , Processed in 0.073173 second(s), 57 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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