文档库 最新最全的文档下载
当前位置:文档库 › 临界段

临界段

临界段.txt爱尔兰﹌一个不离婚的国家,一个一百年的约定。难过了,不要告诉别人,因为别人不在乎。★ 真话假话都要猜,这就是现在的社会。 临界段.txt我退化了,到现在我还不会游泳,要知道在我出生之前,我绝对是游的最快的那个

其实很简单:
临界段就是不可中断的程序段,比如从UART中读取当前传递回来的值,如果有UART中断,此时这个值又会改变。同样临界段就是保护
这类全局变量,如在读取时间节拍时,不应该被时钟更新时钟节拍标志。
实现方法:就是关中断而已。
关中断有3种情况:1:虽关了中断还是可以有中断产生,那就是临界段本身开了中断?这种方法不管他,没有用
2:清全局中断标志,这样是临界段完了后中断也是关的,不能回到临界前的状态
3:关全局中断前,保存全局中断标志,临界段后恢复。与2的区别是如果关全局中断前是开了全局中断的,3就可以恢复,而2不行,如果关全局中断前本身就是关的2,3一样。
注意:STM32有PRIMASK异常全局中断和faults故障全局中断,林阶段不用关faults
PRIMASK和faults是程序状态寄存器CPSR的位。因此可以保存CPSR或者保存PRIMASK和faults如下是这两种方法



#define OS_CRITICAL_METHOD 3


#if OS_CRITICAL_METHOD == 3
#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
#endif

;函数返回值存储在R0中
OS_CPU_SR_Save
MRS R0, PRIMASK ;保存全局中断标志 ; Set prio int mask to mask all (except faults除了故障中断)
CPSID I ;关中断
BX LR
;通过R0传递参数
OS_CPU_SR_Restore
MSR PRIMASK, R0 ;恢复全局中断标志
BX LR












UCOS开关中断函数移植

OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()用来关中断和开中断。在执行临界段代码时要关中断,如果中断打开,临界段代码中的一些全局变量值可能会被中断服务子程序代码改变,或者因为中断引起的任务切换被其它任务函数改变。

何谓“临界段”?在网上搜了下:

临界段也称为关键代码段,它是指一个小代码段。在它能够执行前,它必须独占对某些共享资源的访问权。一旦线程执行进入了临界段。就意味着它获得了这些共享资源的访问权。那么在该线程处于临界段内的期间,其它同样需要独占这些共享资源的线程就必须等待,直到获得资源的线程离开临界段而释放资源。



在LPC2214上移植这两个函数。

在OS_CPU.H中定义

采用第三种实现方法:

#define OS_CRITICAL_METHOD 3

定义一个数据类型OS_CPU_SR

typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR =

32 bits) */

采用第3中方式,需要在UCOS-II函数中定义一个变量:

OS_CPU_SR cpu_sr;

用来保存CPU的状态寄存器值。

定义关中断宏和开中断宏

#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}

#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}

函数声明:

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR OS_CPU_SR_Save(void);

void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);

#endif

以上都是在OS_CPU.H文件中的。



NO_INT EQU 0xC0 ; Mask used to disable interrupts (Both FIR and IRQ)

OS_CPU_SR_Save()和OS_CPU_SR_Restore()函数用汇编语言编写,在OS_CPU_A.S文件中

OS_CPU_SR_Save

MRS R0,CPSR 1

ORR R1,R0,#NO_INT 2

MSR CPSR_c,R1 3

MRS R1,CPSR 4



AND R1,R1,#NO_INT 5

CMP R1,#NO_INT 6

BNE OS_CPU_SR_Save 7

MOV PC,LR 8

1- 读CPSR,把CPSR的值送到R0

2- 把R0和常量#NO_INT相或,结果送给R1,把F和I位置1,禁止IRQ中断和FIQ中断。

3- 把R1的值送给CPSR的低8位,CPSR_c的_c是位域,指CPSR的低8位。

4- 把修改后的CPSR值送到R1

5- R1的值和#NO_INT相与,结果送到R1

6- 比较R1和#NO_INT是否相等

7- 不相等,跳到OS_CPU_SR_Save重新关中断,直到相等。

8- LR保存的是在调用OS_CPU_SR_Save函数时的断点地址,把LR的值送到PC,退出OS_CPU_SR_Save函数,开始执行临界段代码。这条命令的功能相当于51中的RET。

注意:ARM中调用子程序时不会自动保存CPSR的值到SPSR,所以子程序返回时,执行MOV PC,LR也不会把SPSR的值返回到CPSR。这是ARM种调用子程序和进入中断的区别。

汇编函数的返回值是通过R0返回的,把修改前的CPSR值保存到cpu_sr.



OS_CPU_SR_Restore

MSR CPSR_c,R0 1

MOV PC,LR 2

1- 把R0的值送到CPSR的低8位。

在ARM中用R0传递函数的参数,这句指令就是把保存在cpu_sr中的值送到CPSR低8位。高24位没有修改。为什么不直接用MSR CPSR,R0呢?因为ARM指令中规定MSR命令中,CPSR必须指定位域。把这句改成MSR CPSR_cxsf,R0,即把R0的32位都送给CPSR,应该也没问题。不过在OS_CPU_SR_Save函数中,CPSR的高24位并没有改变。所以这里只需要把保存在cpu_sr中的低8位送到CPSR就可以了。

2-退出OS_CPU_SR_Restore函数。

相关文档