RT-Thread内核-- Cortex-M 临界段代码保护

临界段用一句话概括就是一段在执行的时候不能被中断的代码段。 
那么什么情况下临界段会被打断?一个是系统调度,还有一个就是外部中断。在RT-Thread,系统调度,最终也是产生PendSV中断,在PendSV Handler里面实现线程的切换,所以还是可以归结为中断。 既然这样,RT-Thread对临界段的保护就处理的很干脆了,直接把中断全部关了,NMI FAULT和硬FAULT除外。
为了快速地关中断,Cortex-M内核专门设置了一条CPS指令,有4种用法
CPSID I;PRIMASK = 1;关中断
CPSIE I;PRIMASK = 0;开中断
CPSID F;FAULTMASK = 1;关异常
CPSIE F;FAULTMASK = 0;开异常
Cortex-M3的中断屏蔽寄存器组(属于特殊功能寄存器)
这三个寄存器用于控制异常的使能和除能
1、PRIMASK:这是个只有1个位的寄存器。当它置1时, 就关掉所有可屏蔽的异常,只剩下NMI和硬fault可以响应。它的缺省值是0,表示没有关中断。
2、FAULTMASK:这是个只有1个位的寄存器。当它置1时,只有NMI才能响应,所有其它的异常,包括中断和fault,通通闭嘴。它的缺省值也是0,表示没有关异常。
3、BASEPRI:这个寄存器最多有9位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成0,则不关闭任何中断,0也是缺省值。
对于时间‐关键任务而言,PRIMASK和BASEPRI对于暂时关闭中断是非常重要的。而FAULTMASK则可以被OS用于暂时关闭fault处理机能,这种处理在某个任务崩溃时可能需要。因为在任务崩溃时,常常伴随着一大堆faults。在系统料理“后事”时,通常不再需要响应这些fault——人死帐清。总之FAULTMASK就是专门留给 OS 用的。
特殊功能寄存器只能被专用的MSR和MRS指令访问,并且他们也没有存储器地址
MRS <gp_reg>, <special_reg> ; 读特殊功能寄存器的值到通用寄存器
MSR <special_reg>, <gp_reg> ; 写通用寄存器的值到特殊功能寄存器
要访问PRIMASK,FAULTMASK以及BASEPRI,要使用MRS/MSR指令,如:
MRS R0, BASEPRI   ;读取BASEPRI到R0中
MRS R0, FAULTMASK ;读取FAULTMASK到R0中
MRS R0, PRIMASK   ;读取PRIMASK到R0中
MSR BASEPRI, R0   ;写入R0到BASEPRI中
MSR FAULTMASK, R0 ;写入R0到FAULTMASK中
MSR PRIMASK, R0   ;写入R0到PRIMASK中
这有在特权级下,才允许访问这3个寄存器。

关全局中断

;/*
; * rt_base_t rt_hw_interrupt_disable(void);
; */
rt_hw_interrupt_disable    PROC        ;关键字PROC表示汇编子程序的开始
    EXPORT  rt_hw_interrupt_disable    ;使用EXPORT关键字导出标号rt_hw_interrupt_disable,使其具有全局属性,在外部头文件声明后(在rthw.h),就可以在C文件中调用  rt_base_t rt_hw_interrupt_disable(void);
    MRS     r0, PRIMASK                ;通过MRS指令将特殊功能寄存器PRIMASK的值存储到通用寄存器R0中,当在C中调用汇编子程序返回时,会将R0作为函数的返回值。
    CPSID   I                          ;关闭中断,即使用CPS指令将PRIMASK寄存器的置1
    BX      LR                         ;子程序返回
    ENDP                               ;ENDP表示汇编子程序结束,与PROC成对使用

开全局中断 

;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable    PROC         ;关键字PROC表示汇编子程序的开始
    EXPORT  rt_hw_interrupt_enable     ;使用EXPORT关键字导出标号rt_hw_interrupt_enable,使其具有全局属性,在外部头文件声明后(在rthw.h),就可以在C文件中调用 void rt_hw_interrupt_enable(rt_base_t level)
    MSR     PRIMASK, r0                ;使用MSR指令将通用寄存器R0的值存储到特殊功能寄存器PRIMASK当在C中调用汇编子程序返回时,会将第一个形参传入到通用寄存器R0,所以在C中调用rt_hw_interrupt_enable()的时候,需要传入一个形参,该形参是进入临界段之前保存的PRIMASK的值。
    BX      LR                         ;子程序返回
    ENDP                               ;ENDP表示汇编子程序结束,与PROC成对使用

 临界段代码

PRIMASK = 0; /* PRIMASK 初始值为 0,表示没有关中断 */
rt_base_t level1;
rt_base_t level2;
/* 临界段代码 */
{
/* 临界段 1 开始 */
    level1 = rt_hw_interrupt_disable(); /* 关中断,r0 = PRIMASK = 0, PRIMASK = 1, level1 = r0 =0*/ 
    {
        /* 临界段 2 */
        level2 = rt_hw_interrupt_disable(); /* 关中断,r0 = PRIMASK = 1, PRIMASK = 1, level2 = r0 = 1, */
        {
            
        }
        rt_hw_interrupt_enable(level2); /* 开中断,level2 = 1, r0 = level2 = 1, PRIMASK = r0 = 1 此时中断并没有打开,因为还没有完全离开临界段的范畴,所以不能打开中断*/
    }
    /* 临界段 1 结束 */
    rt_hw_interrupt_enable(level1); /* 开中断,level1 = 0, r0 = level1 = 0, PRIMASK = r0 = 0 */
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值