zoukankan      html  css  js  c++  java
  • 【转载】ucos临界段

        其实很简单:

        临界段就是不可中断的程序段,比如从UART中读取当前传递回来的值,如果有UART中断,此时这个值又会改变。同样临界段就是保护这类全局变量,如在读取时间节拍时,不应该被时钟更新时钟节拍标志。
        实现方法:就是关中断而已。
        关中断有3种情况:
    1:虽关了中断还是可以有中断产生,那就是临界段本身开了中断?(自己理解是临界段内部自己又打开中断)这种方法不管他,没有用
    2:清全局中断标志,这样是临界段完了后中断也是关的,不能回到临界前的状态
    3:关全局中断前,保存全局中断标志,临界段后恢复。与2的区别是如果关全局中断前是开了全局中断的,3就可以恢复,而2不行,如果关全局中断前本身就是关的2,3一样。
    注意:STM32有PRIMASK异常全局中断和faults故障全局中断,林阶段不用关faults PRIMASK和faults是程序状态寄存器CPSR的位。因此可以保存CPSR或者保存PRIMASK和faults如下是这两种方法 
    1. OS_cpu_a.asm文件中:
    2. 1 OS_ENTER_CRITICAL
      2 CPSID I ;Disable all the interrupts
      3 PUSH {R1,R2}
      4 LDR R1,=OSInterrputSum;OSInterrputSum++
      5 LDRB R2,[R1]
      6 ADD R2, R2,#1
      7 STRB R2,[R1]
      8 POP {R1,R2}
      9 BX LR
      View Code
    3.  1 ;/***************************************************************************************
       2 ;* 函数名称: OS_EXIT_CRITICAL
       3 ;*
       4 ;* 功能描述: 退出临界区
       5 ;*
       6 ;* 参 数: None
       7 ;*
       8 ;* 返 回 值: None
       9 ;*****************************************************************************************/
      10 OS_EXIT_CRITICAL
      11 PUSH {R1, R2}
      12 LDR R1,=OSInterrputSum;OSInterrputSum--
      13 LDRB R2,[R1]
      14 SUB R2, R2,#1
      15 STRB R2,[R1]
      16 MOV R1,#0
      17 CMP R2,#0 ; if OSInterrputSum=0,enable
      18 ; interrupts如果OSInterrputSum=0,
      19 MSREQ PRIMASK, R1
      20 POP {R1, R2}
      21 BX LR
      View Code
     1 #define  OS_CRITICAL_METHOD   3
     2 #if OS_CRITICAL_METHOD == 3
     3     #define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
     4     #define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
     5 #endif
     6 ;函数返回值存储在R0中
     7 OS_CPU_SR_Save
     8     MRS     R0, PRIMASK     ;保存全局中断标志  ; Set prio int mask to mask all (except faults除了故障中断)
     9     CPSID   I            ;关中断
    10     BX      LR
    11 ;通过R0传递参数
    12 OS_CPU_SR_Restore
    13     MSR     PRIMASK, R0    ;恢复全局中断标志
    14     BX      LR
    View Code
     
    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函数。
  • 相关阅读:
    从上亿数据中抽取千万数据只需10分钟内
    当硬件成为瓶颈时怎么提高数据仓库的加载?
    监控logshipping 流量
    MSSQLMiRROR
    读取STGMEDIUM中的数据
    一个基本算法题暴露出来的C++基础不扎实
    C++对象模型学习
    从微观看chrome 之一:Singleton<T> 范型类
    从微观看chrome 之二:围绕Profile的ProfileService系统
    DevC++配置问题
  • 原文地址:https://www.cnblogs.com/cposture/p/4291510.html
Copyright © 2011-2022 走看看