¿Cuáles son las diversas formas de deshabilitar y volver a habilitar las interrupciones en los microcontroladores STM32 para implementar protecciones de acceso atómicas?

16 minutos de lectura

avatar de usuario
grapas gabriel

La técnica estándar para hacer cumplir el acceso atómico a las variables volátiles compartidas con los ISR, a través de “guardias de acceso atómico” o “guardias de interrupción”, es la siguiente:

// 1. save interrupt state
// 2. disable only the interrupts necessary

// you get atomic access to volatile variables shared with ISRs here

// 3. restore interrupt state

Vea también donde describo esto en detalle aquí, incluidas las mejores prácticas (mantenga las interrupciones apagadas por un período corto de tiempo) y cómo hacer lecturas atómicas SIN deshabilitar las interrupciones primeroa través de mi doAtomicRead() función repetir-leer-bucle: Lectura de una variable de 64 bits que es actualizada por un ISR.

Previamente he documentado cómo hacer esto para los microcontroladores AVR/Arduino: ¿Cómo fuerzo la atomicidad en Atmel AVR mcus/Arduino?

Pero, ¿cómo hago esto para los microcontroladores STM32? Sé que hay muchas maneras.

Por favor, cubra las siguientes técnicas:

  1. A través de ARM-core CMSIS:
    1. para interrupciones globales
    2. para IRQ específicas (Solicitudes de interrupción)
  2. Vía STM32 HAL (capa de abstracción de hardware)
  3. A través de FreeRTOS

Esta respuesta está relacionada, pero es insuficiente: ¿Cómo puedo volver a habilitar la interrupción externa de stm32f103 después de deshabilitarla?

avatar de usuario
tom v

El acceso atómico a las variables compartidas solo debe lograrse desactivando las interrupciones donde no hay alternativas más modernas disponibles o, a veces, en proyectos muy simples donde el rendimiento y la latencia no son un problema.

La desactivación de las interrupciones aumenta la latencia del sistema de formas que son difíciles de predecir y se deben evitar siempre que sea posible.

En ARMv7M y núcleos superiores (incluidos todos los STM32F1xx, STM32F2xx, STM32F3xx, STM32F4xx, STM32F7xx, STM32H7xx, STM32G4xx, STM32L1xx, STM32L4xx, SRM32L5xx, STM32U5xx), el acceso atómico debe lograrse mediante las instrucciones de acceso exclusivo LDREX/STREX. Se pueden construir colas de mensajes complejas y sistemas de semáforos sobre estas primitivas que nunca requieren desactivar las interrupciones. Para un ejemplo mira la implementación del semáforo en mbed-os.

Los otros miembros de la familia STM32 (STM32F0xx, STM32G0xx y STM32L0xx) pueden desactivar interrupciones individuales usando NVIC_EnableIRQ/NVIC_EnableIRQ o como último recurso apague todas las interrupciones con __disable_irq()/__enable_irq().

  • ¿Puedes dar una demostración? ¿Funciona en AVR mcus? STM32 mcus?

    – Gabriel grapas

    26 de marzo a las 9:21


  • Demuéstrelo en código para STM32 sin sistema operativo.

    – Gabriel grapas

    26 de marzo a las 9:26

  • AFAIK, las instrucciones LDREX/STREX no están disponibles en los núcleos Cortex M0. Aún así, std::atomic funciona para acceso de lectura o escritura, pero no para ++ o — . No recuerdo qué instrucciones usa en M0. No lo he intentado, pero supongo que C11 _Atomic funciona de manera similar.

    – Tagli

    26 de marzo a las 19:16

  • @Tagli Tienes toda la razón, he editado mi respuesta de manera significativa.

    – Tom V

    26 mar a las 21:00

avatar de usuario
grapas gabriel

Múltiples formas de habilitar/deshabilitar interrupciones en STM32 mcus:

1. A través de ARM-core CMSIS:

A. Para interrupciones globales

__enable_irq()   // enable all interrupts
__disable_irq()  // disable all interrupts

// Returns the current state of the priority mask bit from the Priority Mask
// Register. [0 if global interrupts are **enabled** and non-zero if they
// are **disabled**]
__get_PRIMASK()

Para la definición de estas funciones, véase:

  1. https://github.com/ARM-software/CMSIS/blob/master/CMSIS/Include/cmsis_gcc.h
    1. Contiene al menos:
      __enable_irq() 
      __disable_irq()
      __get_PRIMASK()
      __set_PRIMASK()
      
  2. Ubicación de ejemplo de STM32: “stm/stm32f2xx/st_hal_v1.1.3/CMSIS/Include/cmsis_gcc.h”:

Para guardar y restaurar el estado de interrupciónusar __get_PRIMASK()Me gusta esto:

// 1. back up interrupt state; `__get_PRIMASK()` returns 0 if interrupts
// are **enabled**, and non-zero if they are **disabled**.
bool interrupts_enabled = (__get_PRIMASK() == 0);

// do stuff

// 2. Disable interrupts
__disable_irq();
// 3. Restore backed-up-state
if (interrupts_enabled) {
    __enable_irq();
}

Cuando se trata de interrupciones globales, ¡esta es la mejor manera para el código completo, que no es FreeRTOS!

yo pensar esta técnica también es compatible con TODOS los mcus ARM-core, no solo con STM32.

Primero aprendí esta técnica de Tilen Majerle, aquí: https://stm32f4-discovery.net/2015/06/how-to-habilitar-deshabilitar-interrupciones-en-brazo-cortex-m/. ¡Su trabajo y contribuciones para aclarar estas cosas súper ofuscadas son infinitamente valiosas y apreciadas!

Su ejemplo:

void ImportantFunction1(void) {
    /* Important function 1 */
    uint32_t prim;
    
    /* Do some stuff here which can be interrupted */
    
    /* Read PRIMASK register, check interrupt status before you disable them */
    /* Returns 0 if they are enabled, or non-zero if disabled */
    prim = __get_PRIMASK();
    
    /* Disable interrupts */
    __disable_irq();
    
    /* Do some stuff here which can not be interrupted */
    
    /* Call subfunction */
    ImportantFunction2();
    
    /* Do some stuff here which can not be interrupted */
    /* This part is still interrupt safe because ImportantFunction2 will not enable interrupts */
    
    /* Enable interrupts back */
    if (!prim) {
        __enable_irq();
    }
    
    /* Do some stuff here which can be interrupted */
}

B. Para IRQ específicas (Solicitudes de interrupción)

Es mejor evitar deshabilitar interrupciones globalessi es posible, y deshabilite solo el menor número de interrupciones específicas posibles para lograr atomicidad para su código específico. Por lo tanto, el uso de estas funciones le permite habilitar o deshabilitar solo el interrupciones específicas ¡necesitas!

Habilitar o deshabilitar tipos específicos de interrupciones:

void NVIC_EnableIRQ(IRQn_Type IRQn);
void NVIC_DisableIRQ(IRQn_Type IRQn);

NVIC significa “Controlador de interrupción de vector anidado”. interrupciones anidadas (es decir: una interrupción de mayor prioridad aún puede dispararse dentro de una ISR) son activado por defecto en los microcontroladores STM32. Cada tipo de interrupción tiene una prioridad asignada, con números de menor prioridad ser mayor prioridad, y las interrupciones de mayor prioridad pueden dispararse mientras se procesa una ISR para una interrupción de menor prioridad. Consulte aquí para obtener un poco más de información sobre el STM32 NVIC: https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-nvic-or-nested-vector-interrupt-controller/.

Contraste esto con los microcontroladores AVR (por ejemplo, ATMega328 / Arduino Uno), que no no tener interrupciones basadas en prioridad, por lo que por defecto, cuando ninguna ISR está siendo procesado, todos interrupciones (es decir, interrupciones globales) son deshabilitado automáticamente a medida que el programa ingresa al ISR. Sin embargo, tenga en cuenta que incluso en AVR mcus, aún puede habilitar manualmente interrupciones anidadas / ISR si lo desea por a mano volver a habilitar interrupciones globales dentro de su ISR, a través de una llamada a interrupts() en arduino o sei() (establecer interrupciones) en AVR sin formato.

Creo que cada fabricante de microcontroladores ARM-core, incluidos los tipos STM32, debe definir y crear su propia lista de IRQn_Type tipos de solicitud de interrupciónasí que vea a continuación los detalles de STM32 sobre sus tipos de interrupción específicos definidos para cada mcu.

2. A través de las bibliotecas STM32 HAL (Capa de abstracción de hardware)

Habilitar o deshabilitar tipos específicos de interrupciones:

// enable interrupts
HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
// disable interrupts 
HAL_NVIC_DisableIRQ(IRQn_Type IRQn);

Consulte, por ejemplo: “stm/stm32f2xx/st_hal_v1.1.3/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_cortex.c/.h”: las definiciones de las funciones anteriores se encuentran en esos archivos. Véalos en línea:

  1. https://github.com/STMicroelectronics/STM32CubeF2/blob/master/Drivers/STM32F2xx_HAL_Driver/Inc/stm32f2xx_hal_cortex.h#L264-L265
  2. https://github.com/STMicroelectronics/STM32CubeF2/blob/master/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_cortex.c#L178-L210

Aquí están las definiciones de HAL_NVIC_EnableIRQ() y HAL_NVIC_DisableIRQ(). Tenga en cuenta que solo verifican para asegurarse de que su IRQn es válido, luego pasan el argumento de entrada al CMSIS ARM-core NVIC_EnableIRQ() y NVIC_DisableIRQ() funciones arriba!:

/**
  * @brief  Enables a device specific interrupt in the NVIC interrupt controller.
  * @note   To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
  *         function should be called before. 
  * @param  IRQn External interrupt number.
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f2xxxx.h))
  * @retval None
  */
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
{
  /* Check the parameters */
  assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
  
  /* Enable interrupt */
  NVIC_EnableIRQ(IRQn);
}

/**
  * @brief  Disables a device specific interrupt in the NVIC interrupt controller.
  * @param  IRQn External interrupt number.
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f2xxxx.h))
  * @retval None
  */
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)
{
  /* Check the parameters */
  assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
  
  /* Disable interrupt */
  NVIC_DisableIRQ(IRQn);
}

Para IRQn_Types: vea el archivo de definición apropiado para su tablero específico! Estas son definiciones específicas de placa, para su placa de su fabricante. Aquí están todas las placas de la línea STM32 F2xx, por ejemplo: https://github.com/STMicroelectronics/STM32CubeF2/tree/master/Drivers/CMSIS/Device/ST/STM32F2xx/Include. Miremos el stm32f217xx.h archivo específicamente:

  1. https://github.com/STMicroelectronics/STM32CubeF2/blob/master/Drivers/CMSIS/Device/ST/STM32F2xx/Include/stm32f217xx.h
  2. Vista sin formato (ya que el archivo es demasiado grande para verlo en GitHub de lo contrario): https://raw.githubusercontent.com/STMicroelectronics/STM32CubeF2/master/Drivers/CMSIS/Device/ST/STM32F2xx/Include/stm32f217xx.h

Desde este archivo, podemos ver el typedef enum definición para el IRQn_Type, que es la “Definición de número de interrupción STM32F2XX”. Esto es lo que parece:

/**
 * @brief STM32F2XX Interrupt Number Definition, according to the selected device 
 *        in @ref Library_configuration_section 
 */
typedef enum
{
/******  Cortex-M3 Processor Exceptions Numbers ****************************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                          */
  HardFault_IRQn              = -13,    /*!< 3 Hard Fault Interrupt                                            */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt                           */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                                   */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                                 */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                                    */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                              */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                                    */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                                */
/******  STM32 specific Interrupt Numbers **********************************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                                         */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt                         */
  TAMP_STAMP_IRQn             = 2,      /*!< Tamper and TimeStamp interrupts through the EXTI line             */
  RTC_WKUP_IRQn               = 3,      /*!< RTC Wakeup interrupt through the EXTI line                        */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                                            */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                              */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                              */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                              */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                              */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                              */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                              */
  DMA1_Stream0_IRQn           = 11,     /*!< DMA1 Stream 0 global Interrupt                                    */
  DMA1_Stream1_IRQn           = 12,     /*!< DMA1 Stream 1 global Interrupt                                    */
  DMA1_Stream2_IRQn           = 13,     /*!< DMA1 Stream 2 global Interrupt                                    */
  DMA1_Stream3_IRQn           = 14,     /*!< DMA1 Stream 3 global Interrupt                                    */
  DMA1_Stream4_IRQn           = 15,     /*!< DMA1 Stream 4 global Interrupt                                    */
  DMA1_Stream5_IRQn           = 16,     /*!< DMA1 Stream 5 global Interrupt                                    */
  DMA1_Stream6_IRQn           = 17,     /*!< DMA1 Stream 6 global Interrupt                                    */
  ADC_IRQn                    = 18,     /*!< ADC1, ADC2 and ADC3 global Interrupts                             */
  CAN1_TX_IRQn                = 19,     /*!< CAN1 TX Interrupt                                                 */
  CAN1_RX0_IRQn               = 20,     /*!< CAN1 RX0 Interrupt                                                */
  CAN1_RX1_IRQn               = 21,     /*!< CAN1 RX1 Interrupt                                                */
  CAN1_SCE_IRQn               = 22,     /*!< CAN1 SCE Interrupt                                                */
  EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                                     */
  TIM1_BRK_TIM9_IRQn          = 24,     /*!< TIM1 Break interrupt and TIM9 global interrupt                    */
  TIM1_UP_TIM10_IRQn          = 25,     /*!< TIM1 Update Interrupt and TIM10 global interrupt                  */
  TIM1_TRG_COM_TIM11_IRQn     = 26,     /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */
  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                                    */
  TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                             */
  TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                             */
  TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt                                             */
  I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                              */
  I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                              */
  I2C2_EV_IRQn                = 33,     /*!< I2C2 Event Interrupt                                              */
  I2C2_ER_IRQn                = 34,     /*!< I2C2 Error Interrupt                                              */  
  SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                             */
  SPI2_IRQn                   = 36,     /*!< SPI2 global Interrupt                                             */
  USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                                           */
  USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                                           */
  USART3_IRQn                 = 39,     /*!< USART3 global Interrupt                                           */
  EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                                   */
  RTC_Alarm_IRQn              = 41,     /*!< RTC Alarm (A and B) through EXTI Line Interrupt                   */
  OTG_FS_WKUP_IRQn            = 42,     /*!< USB OTG FS Wakeup through EXTI line interrupt                     */    
  TIM8_BRK_TIM12_IRQn         = 43,     /*!< TIM8 Break Interrupt and TIM12 global interrupt                   */
  TIM8_UP_TIM13_IRQn          = 44,     /*!< TIM8 Update Interrupt and TIM13 global interrupt                  */
  TIM8_TRG_COM_TIM14_IRQn     = 45,     /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
  TIM8_CC_IRQn                = 46,     /*!< TIM8 Capture Compare Interrupt                                    */
  DMA1_Stream7_IRQn           = 47,     /*!< DMA1 Stream7 Interrupt                                            */
  FSMC_IRQn                   = 48,     /*!< FSMC global Interrupt                                             */
  SDIO_IRQn                   = 49,     /*!< SDIO global Interrupt                                             */
  TIM5_IRQn                   = 50,     /*!< TIM5 global Interrupt                                             */
  SPI3_IRQn                   = 51,     /*!< SPI3 global Interrupt                                             */
  UART4_IRQn                  = 52,     /*!< UART4 global Interrupt                                            */
  UART5_IRQn                  = 53,     /*!< UART5 global Interrupt                                            */
  TIM6_DAC_IRQn               = 54,     /*!< TIM6 global and DAC1&2 underrun error  interrupts                 */
  TIM7_IRQn                   = 55,     /*!< TIM7 global interrupt                                             */
  DMA2_Stream0_IRQn           = 56,     /*!< DMA2 Stream 0 global Interrupt                                    */
  DMA2_Stream1_IRQn           = 57,     /*!< DMA2 Stream 1 global Interrupt                                    */
  DMA2_Stream2_IRQn           = 58,     /*!< DMA2 Stream 2 global Interrupt                                    */
  DMA2_Stream3_IRQn           = 59,     /*!< DMA2 Stream 3 global Interrupt                                    */
  DMA2_Stream4_IRQn           = 60,     /*!< DMA2 Stream 4 global Interrupt                                    */
  ETH_IRQn                    = 61,     /*!< Ethernet global Interrupt                                         */
  ETH_WKUP_IRQn               = 62,     /*!< Ethernet Wakeup through EXTI line Interrupt                       */
  CAN2_TX_IRQn                = 63,     /*!< CAN2 TX Interrupt                                                 */
  CAN2_RX0_IRQn               = 64,     /*!< CAN2 RX0 Interrupt                                                */
  CAN2_RX1_IRQn               = 65,     /*!< CAN2 RX1 Interrupt                                                */
  CAN2_SCE_IRQn               = 66,     /*!< CAN2 SCE Interrupt                                                */
  OTG_FS_IRQn                 = 67,     /*!< USB OTG FS global Interrupt                                       */
  DMA2_Stream5_IRQn           = 68,     /*!< DMA2 Stream 5 global interrupt                                    */
  DMA2_Stream6_IRQn           = 69,     /*!< DMA2 Stream 6 global interrupt                                    */
  DMA2_Stream7_IRQn           = 70,     /*!< DMA2 Stream 7 global interrupt                                    */
  USART6_IRQn                 = 71,     /*!< USART6 global interrupt                                           */
  I2C3_EV_IRQn                = 72,     /*!< I2C3 event interrupt                                              */
  I2C3_ER_IRQn                = 73,     /*!< I2C3 error interrupt                                              */
  OTG_HS_EP1_OUT_IRQn         = 74,     /*!< USB OTG HS End Point 1 Out global interrupt                       */
  OTG_HS_EP1_IN_IRQn          = 75,     /*!< USB OTG HS End Point 1 In global interrupt                        */
  OTG_HS_WKUP_IRQn            = 76,     /*!< USB OTG HS Wakeup through EXTI interrupt                          */
  OTG_HS_IRQn                 = 77,     /*!< USB OTG HS global interrupt                                       */
  DCMI_IRQn                   = 78,     /*!< DCMI global interrupt                                             */
  CRYP_IRQn                   = 79,     /*!< CRYP crypto global interrupt                                      */
  HASH_RNG_IRQn               = 80      /*!< Hash and Rng global interrupt                                     */
} IRQn_Type;

Ejemplo de uso usando STM32 HAL:

Llegar acceso exclusivo (para garantizar que las cadenas se impriman atómicamente, por ejemplo) al USART1 para imprimir caracteres de depuración a través de un modo de bloqueo (sondeado) basado en HAL (es decir, a través de HAL_UART_Transmit()), necesita deshabilitar todas las interrupciones para USART1_IRQn haciendo lo siguiente. (Esto garantiza que obtenga acceso atómico a este dispositivo):

// 1. Disable the UART IRQ
HAL_NVIC_DisableIRQ(USART1_IRQn);

// 2. Send your string (in HAL blocking/polled mode)
// Prototype for this function is from 
// "...stm/stm32f7xx/st_hal_v1.1.2/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart.c": 
// - `HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, 
//        uint8_t *pData, uint16_t Size, uint32_t Timeout)`
// Note: `huart` is defined by STM32CubeMX as `UART_HandleTypeDef huart1;` 
// in "hal_source/Src/usart.c"
HAL_UART_Transmit(&huart1, (uint8_t *)my_str, strlen(my_str), HAL_MAX_DELAY);

// 3. Enable the UART_IRQ
// FUTURE WORK: make this nestable/more robust by only enabling the 
// IRQ here if it was previously enabled before disabling it!
HAL_NVIC_EnableIRQ(USART1_IRQn);

3. A través de FreeRTOS:

Las funciones relacionadas con atomic-access-guard / interrupt de FreeRTOS se enumeran en la sección “Módulos” de la API de control del kernel aquí: Control del núcleo:

taskYIELD()
taskENTER_CRITICAL()            // interrupts off
taskEXIT_CRITICAL()             // restore interrupts
taskENTER_CRITICAL_FROM_ISR()   // interrupts off
taskEXIT_CRITICAL_FROM_ISR()    // restore interrupts
taskDISABLE_INTERRUPTS()        // interrupts off
taskENABLE_INTERRUPTS()         // interrupts on

A. Macros de nivel superior:

  1. ¡Estas son las macros preferidas para usar, y son las recomendadas por freertos!
  2. Todos estos admiten llamadas anidadas y terminan llamando portDISABLE_INTERRUPTS() de todos modos, cuál es la implementación del puerto del nivel inferior taskDISABLE_INTERRUPTS()mostrado a continuación.
  3. Desde: https://www.freertos.org/taskENTER_CRITICAL_taskEXIT_CRITICAL.html
    taskENTER_CRITICAL()        // interrupts off
    taskEXIT_CRITICAL()         // restore interrupts
    
  4. Desde: https://www.freertos.org/taskENTER_CRITICAL_FROM_ISR_taskEXIT_CRITICAL_FROM_ISR.html
    taskENTER_CRITICAL_FROM_ISR()
    taskEXIT_CRITICAL_FROM_ISR()
    

B. Macros de nivel inferior:

  1. ¡Estos NO admiten llamadas anidadas!

  2. La documentación oficial sobre ellos se encuentra en la página principal. “Control del núcleo” página:

    taskDISABLE_INTERRUPTS()
    taskENABLE_INTERRUPTS()
    
  3. Notas y limitaciones:

    1. taskDISABLE_INTERRUPTS() en el enlace de arriba dice:

    Normalmente esta macro no sería llamada directamente y taskENTER_CRITICAL() y taskEXIT_CRITICAL() debe usarse en su lugar.

    1. taskENABLE_INTERRUPTS() en el enlace de arriba dice:

    Normalmente esta macro no sería llamada directamente y taskENTER_CRITICAL() y taskEXIT_CRITICAL() debe usarse en su lugar.

    1. Nótese también que el uso de taskDISABLE_INTERRUPTS() se demuestra como la técnica utilizada para entrar en pánico dentro de una definición de macro de ejemplo para configASSERT().
      1. De aquí: https://www.freertos.org/a00110.html#configASSERTcuando se usa con un depurador, se define como:
        /* Define configASSERT() to disable interrupts and sit in a loop. */
        #define configASSERT( ( x ) )     if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
        
      2. Mis pensamientos: tal vez en este caso (es decir, afirmación dura o pánico), taskDISABLE_INTERRUPTS() podría ser preferible a taskENTER_CRITICAL() porque no hay cantidad de llamadas taskEXIT_CRITICAL() de otro hilo volverá a habilitar las interrupciones una vez taskDISABLE_INTERRUPTS() ha sido llamado [I think!?]–más bien, uno tendría que llamar explícitamente (y accidentalmente) taskENABLE_INTERRUPTS() (por ejemplo: de otro hilo) para volver a habilitar las interrupciones una vez taskDISABLE_INTERRUPTS() ha sido llamado. En otras palabras, usando el nivel bajo taskDISABLE_INTERRUPTS() llamada es apropiada aquí porque realmente hará que el sistema se siente en un bucle, como se desea, mientras que taskENTER_CRITICAL() no lo haría

Mutexes y otras primitivas de sincronización habilitadas para SO (sistema operativo)

Más allá de los ejemplos anteriores, también puede usar FreeRTOS colas (que son seguros para subprocesos, diferente a todos los contenedores en la biblioteca estándar de C++), mutexes, semáforos, notificaciones de tareasy otras primitivas de sincronización, cuando sea posible y apropiado, para proteger ciertos datos que se comparten entre Tareas de FreeRTOS (subprocesos), suponiendo que esté ejecutando FreeRTOS.

Vea la lista de estas herramientas aquí: https://www.freertos.org/a00106.htmly en los menús de navegación de la izquierda una vez que haga clic en ese enlace.

Ver también:

  1. Mi respuesta sobre esto para AVR mcus/Arduino
  2. Mi respuesta sobre la práctica general y demostración de utilizando guardias de acceso atómico, y mi doAtomicRead() func que asegura el acceso atómico sin apagar las interrupciones
  3. [my Q&A] ¿Qué tipos/tamaños de variables son atómicos en los microcontroladores STM32?
  4. [my answer] Programación de STM32 como STM8 (GPIO a nivel de registro)

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad