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; 开异常
3、关中断
;/* ; * 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,
(5)子程序返回
(6)ENDP表示汇编子程序结束,与PROC成对使用。
4、开中断
;/* ; * 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 指令就行了