• RT-Thread 之临界段保护


    1、什么是临界段

    临界段就是一段在执行的时候不能被中断的代码段。在RT-Thread里面这个临界段最常出现的就是对全局变量的操作。

      那么什么情况下临界段会被打断? 一个是系统调度,另一个是外部中断。在RT-Thread里面,系统调度,最终也是产生PendSV中断,在PendSV Handler里面实现线程的切换。所以还是可以归结为中断。既然这样,RT-Thread对临界段的保护就处理得很干脆了,直接把中断全部关了,NMIFAULT和硬FAULT除外。

    2、cortex-M 内核快速关中断指令

    为了快速开关中断,cortex-M 内核专门设置了一条CPS指令,有4种用法,具体如下:

    CPSID I ;PRIMASK=1 ; 关中断
    CPSIE I ;PRIMASK=0 ; 开中断
    CPSID F ;FAULTMASK=1; 关异常
    CPSIE F ;FAULTMASK=0; 开异常
    PRIMASK 和 FAULTMASK 是 Cortex-M 内核里面三个中断屏蔽寄存器中的两个,还有一个是 BASEPRI,有关这三个寄存器的详细用法见下表。

     3、关中断

    RT-Thread 关中断的函数在 contex_rvds.s 中定义,在 rthw.h 中声明,具体实现:
    ;/*
    ; * rt_base_t rt_hw_interrupt_disable();
    ; */
    rt_hw_interrupt_disable PROC;         (1)
    EXPORT rt_hw_interrupt_disable;      (2)
    MRS r0, PRIMASK;                      (3)
    CPSID I;                             (4)
    BX LR;                               (5)
    ENDP;                                 (6)    

    (1)关键字PROC表示汇编子程序的开始

    (2)使用EXPORT 关键字导出标号 rt_hw_interrupt_disable,使其具有全局属性,在外部头文件声明后(在rthw.h中声明),就可以在C文件中调用。

    (3)通过MRS指令将特殊寄存器PRIMASK的值存储到通用寄存器r0中,当在C中调用汇编子程序返回时,会将r0作为函数返回值。所以在C中调用rt_hw_interrupt_disable()时,需要事先声明一个变量用来存储rt_hw_interrupt_disable()的返回值,即r0寄存器的值,也就是PRIMASK的值。

    (4)关闭中断,即使用CPS指令将PRIMASK寄存器的值置1,

    在这里,我敢肯定,一定会有人有这样一个疑问:关中断,不就是直接使用 CPSID I 指令就行了嘛,为什么还要第三步,即在执行 CPSIDI 指令前,要先把 PRIMASK 的值保存起来?这个疑问接下来在“临界段代码的应用”这个小结揭晓。

    (5)子程序返回

    (6)ENDP表示汇编子程序结束,与PROC成对使用。

    4、开中断

    RT-Thread 开中断的函数在 contex_rvds.s 中定义,在 rthw.h 中声明,具体实现见:
    ;/*
    ; * void rt_hw_interrupt_enable(rt_base_t level);
    ; */
    rt_hw_interrupt_enable PROC;         (1)
    EXPORT rt_hw_interrupt_enable;       (2)
    MSR PRIMASK, r0                      (3)
    BX LR;                               (4)
    ENDP;                                (5)

     (1)关键字PROC表示汇编子程序开始。

    (2)使用EXPORT导出标号rt_hw_interrupt_disable(),使其具有全局属性,在外部头文件中声明后(在rthw.h中声明),就可以在C文件中调用。

    (3)通过MRS指令将通用寄存器r0的值存储到特殊寄存器PRIMASK中,当在C中调用汇编子程序返回时,会将第一个形参传入到通用寄存器r0。所以在C中调用rt_hw_interrupt_disable()的时候,需要传入一个形参。该形参是进入临界段之前保存的PRIMASK的值。这个时候又有人会问,开中断,不就是使用 CPSIE I 指令就行了

    嘛,为啥跟我等凡人想的不一样?其中奥妙将在接下来“临界段代码的应用”这个小结揭晓。
    (4)子程序返回
    (5)ENDP汇编子程序结束,与PROC成对使用。
  • 相关阅读:
    虚树学习笔记
    CF487E Tourists
    [HNOI/AHOI2018]毒瘤
    [HEOI2014]大工程
    hive初始化元数据报错
    layui简单的两个页面
    springboot配置swagger信息入门2
    spark连接hive出现错误,javax.jdo.JDODataStoreException: Required table missing : "`DBS`" in Catalog "" Schema ""
    springboot整合shiro关于任务入门3
    Flink部署Standalone模式
  • 原文地址:https://www.cnblogs.com/tansuoxinweilai/p/14956689.html
Copyright © 2020-2023  润新知