STM32中__HAL_RCC_GPIOA_CLK_ENABLE()冗余代码是否有特殊功能?
关于STM32 HAL时钟使能宏中冗余代码的疑问
我并非想要引发HAL相关论战,而是好奇这段代码是否具备高阶功能。在使用STM32设备的GPIO时,需要通过__HAL_RCC_GPIOA_CLK_ENABLE()来使能GPIO时钟。深入查看代码后,我发现该宏的具体实现如下。在我看来,这段代码中只有SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);这一行是有用的,其余部分似乎都是无用的冗余代码。我能理解__IO uint32_t tmpreg;和UNUSED(tmpreg);存在的原因,但tmpreg = READ_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);这一行似乎没有实际作用,因此这三行代码看起来都毫无意义。我是否忽略了什么?
相关宏定义
#define __HAL_RCC_GPIOA_CLK_ENABLE() \ do { \ __IO uint32_t tmpreg; \ SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);\ tmpreg = READ_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);\ UNUSED(tmpreg); \ } while(0)
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define UNUSED(X) (void)X /* To avoid gcc/g++ warnings */
解答
这段读寄存器的代码并非冗余,核心作用是确保时钟使能操作的内存屏障(Memory Barrier)效果,保证硬件能及时响应配置:
- 硬件同步需求:STM32的RCC寄存器属于外设总线,写操作完成后,硬件可能需要几个周期才能完成时钟电路的配置。直接读取同一块寄存器会触发总线同步操作,迫使CPU等待写操作的结果真正生效,避免后续GPIO配置等操作在时钟未完全使能时执行,引发不可预测的错误。
- 规避编译器优化:现代编译器会对无副作用的代码做优化,如果只有
SET_BIT一行,编译器可能会重排甚至延迟执行该操作。而读寄存器是带有实际硬件交互的操作,编译器无法优化掉这个步骤,从而保证写时钟使能位的操作在后续代码之前严格执行。 - UNUSED宏的作用:
UNUSED(tmpreg)只是为了消除未使用变量的编译警告——我们只需要读操作带来的同步效果,不需要使用读取到的值。
简单来说,这行读代码是为了同步CPU和外设硬件的操作时序,看似冗余,实则是保证代码可靠性的必要手段。
内容的提问来源于stack exchange,提问作者misguidedsquid
相关产品推荐
相关产品推荐

