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函数。
  • 相关阅读:
    卡特兰数
    hdu 1023 Train Problem II
    hdu 1022 Train Problem
    hdu 1021 Fibonacci Again 找规律
    java大数模板
    gcd
    object dection资源
    Rich feature hierarchies for accurate object detection and semantic segmentation(RCNN)
    softmax sigmoid
    凸优化
  • 原文地址:https://www.cnblogs.com/cposture/p/4291510.html
Copyright © 2011-2022 走看看