在CMSIS模块中已经提供了原子操作宏,用于操作16位或32位变量,包括ATOMIC_SET_BIT、ATOMIC_CLEAR_BIT、ATOMIC_MODIFY_REG。
该功能是使用LDREX和STREX指令来实现的。可以通过对原子操作的封装实现互斥。 LDREX和STREX指令是Thumb指令集提供的排他加载和排他访问指令,用以实现排他性访问。
我以STM32F407为例分享一下源代码:
/* Use of CMSIS compiler intrinsics for register exclusive access */ /* Atomic 32-bit register access macro to set one or several bits */ #define ATOMIC_SET_BIT(REG, BIT) \ do { \ uint32_t val; \ do { \ val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) /* Atomic 32-bit register access macro to clear one or several bits */ #define ATOMIC_CLEAR_BIT(REG, BIT) \ do { \ uint32_t val; \ do { \ val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) /* Atomic 32-bit register access macro to clear and set one or several bits */ #define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \ do { \ uint32_t val; \ do { \ val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0)