Comprensión de la función de la sección crítica de uCOS: CPU_SR_ALLOC()

    Primero, echemos un vistazo a las funciones relacionadas con la sección crítica : Las funciones relacionadas con la sección crítica en uCOS son las siguientes: Además de la definición de macro #define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0, incluye principalmente dos funciones: desactivar interrupciones y activar interrupciones.

/* 每次进入临界段时,都要在函数中调用宏CPU_SR_ALLOC()。其实从这里可以看出就是在函数中定义了
一个CPU_SR类型的局部变量cpu_sr*/
#define  CPU_SR_ALLOC()      CPU_SR  cpu_sr = (CPU_SR)0


/*进入临界段可以简单的理解为开关中断*/
#define  CPU_CRITICAL_ENTER()  do { CPU_INT_DIS(); } while (0)   //关中断   
#define  CPU_CRITICAL_EXIT()   do { CPU_INT_EN();  } while (0)   //开中断


/*uCOS常常把函数用typedef或者#define重定义为一个描述函数功能的名字,以便用户使用。
所以我们继续查看CPU_INT_DIS()和CPU_INT_EN()实现源码*/
#define  CPU_INT_DIS()    do { cpu_sr = CPU_SR_Save(); } while (0) 
#define  CPU_INT_EN()     do { CPU_SR_Restore(cpu_sr); } while (0) 


/*CPU_SR_Save()和CPU_SR_Restore()是用汇编语言写的,之所以用汇编是因为Cortex内核提供了
PRIMASK寄存器,使用 CPSID I 指令就能立即关闭中断。PRIMASK是只有 1 个位的寄存器。
当它置 1 时,就关掉所有可屏蔽的异常,只剩下 NMI和硬 fault 可以响应。它的缺省值是 0,
表示没有关中断。*/

CPU_SR_Save
        MRS     R0, PRIMASK      ; 关闭中断,只剩下 NMI和硬 fault 可以响应
        CPSID   I
        BX      LR

CPU_SR_Restore               
        MSR     PRIMASK, R0
        BX      LR

    De hecho, después de un gran desvío, las dos funciones de interrupción del interruptor después de ingresar a la sección crítica se implementan en lenguaje ensamblador modificando el valor del registro PRIMASK. Entre ellos, MRS R0 y PRIMASK asignan el valor del registro PRIMASK al registro R0. MSR PRIMASK, R0 asigna el valor del registro R0 al registro PRIMASK. Aquí R0 se utiliza para pasar parámetros. La función secundaria pasa el valor de retorno a la función principal a través del registro R0. Aquí, MRS R0, PRIMASK y el valor de R0 se devuelven cuando se ejecuta la instrucción BX LR. La función principal pasa los parámetros de entrada de la función secundaria a través de R0. Aquí, MSR PRIMASK, R0 debe enviar los parámetros pasados ​​desde la función principal al registro PRIMASK.

   Entonces, ¿por qué se necesita CPU_SR_ALLOC() ? Porque si usa interrupciones de interruptor convencionales, use la instrucción CPSID I para desactivar la interrupción y use la instrucción CPSIE I para activar la interrupción; al anidar secciones críticas, como anidar en una capa: desactive la interrupción 1 - crítica sección - apagar interrupción 2 - sección crítica - abrir interrupción 2 - sección crítica - abrir interrupción 1, la interrupción del interruptor 2 está anidada en la interrupción del interruptor 1; el efecto que queremos es que la interrupción no se pueda activar antes de que se active la interrupción 1 activado, pero la interrupción 2 ya está activada. Si la interrupción se activa mediante instrucciones, no protegerá el código de la sección crítica. Por lo tanto, para evitar que la interrupción se active durante el anidamiento, la función de interrupción del interruptor tiene la operación de pasar parámetros y regresar. De esta manera, activar la interrupción con CPU_SR_Restore () en realidad restaura el estado de interrupción antes de desactivar la interrupción. y en realidad no activa la interrupción, lo que resuelve el problema de las interrupciones anidadas en secciones críticas .

    Entonces, ¿cómo cambia esta situación el uso de una función de interrupción con parámetros de entrada y una función de interrupción con un valor de retorno? El proceso es el siguiente:

/*以一重嵌套为例*/
CPU_SR_ALLOC();  //进入临界段,就是CPU_SR  cpu_sr = (CPU_SR)0;

/*关中断1,就是cpu_sr = CPU_SR_Save();看CPU_SR_Save()源代码,因为PRIMASK初始值尾0,
所以R0是0;然后在CPU_SR_Save()中调用了CPSID  I关闭中断;最后返回R0的值,
所以cpu_sr是等于0*/
CPU_CRITICAL_ENTER();  
{
    临界段代码
    
    /*关中断2,cpu_sr = CPU_SR_Save();通过上面分析已经知道返回的是PRIMASK寄存器的值,
因为关中断1中已经把寄存器值变为1;所以这里cpu_sr=1*/
    CPU_CRITICAL_ENTER();  
    {
        临界段代码
    }
   /*开中断2,就是CPU_SR_Restore(cpu_sr);看CPU_SR_Restore源码,首先将参数cpu_sr存入R0中,
然后赋值给PRIMASK寄存器,因为此时cpu_sr=1,所以PRIMASK值为1;所以不会在这里就开启中断*/
    CPU_CRITICAL_EXIT();   //开中断2

    临界段代码

}
 /*开中断1,就是CPU_SR_Restore(cpu_sr);这里需要手动写一个cpu_sr=0,不然cpu_sr=1,调用
CPU_CRITICAL_EXIT()传给PRIMASK值永远都是1;那就永远不会开启中断*/
cpu_sr = 0;
CPU_CRITICAL_EXIT();   //开中断1

    Para resumir: cuando se llama a una función de interrupción escrita en lenguaje ensamblador en C, se debe pasar un parámetro; al llamar a una función de interrupción, se debe definir una variable para recibir el valor de retorno de la función de interrupción . Debido a que generalmente desactivamos las interrupciones al comienzo de cada sección crítica y las activamos al final de la sección crítica; hay tantas interrupciones de conmutación como secciones críticas; las secciones críticas anidadas no son una excepción. Por lo tanto, cuando se utilizan con frecuencia interrupciones de conmutación, es necesario guardar el estado de conmutación de la interrupción actual del programa. Entonces, lo que se guarda aquí es en realidad el registro PRIMASK que representa el estado de la interrupción. Para desactivar la interrupción, necesita una variable para recibir el valor de retorno. Para activar la interrupción, debe pasar este valor como parámetro a la función. Definir una variable local para recibir los parámetros de retorno y pasar puede evitar la sección crítica errores de anidamiento.

Supongo que te gusta

Origin blog.csdn.net/m0_43443861/article/details/125956776
Recomendado
Clasificación