我并不是想发起一场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)
SET_BIT
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
读取位
#define READ_BIT(REG, BIT) ((REG) & (BIT))
未使用
#define UNUSED(X) (void)X /* To avoid gcc/g++ warnings */
2条答案
按热度按时间1tuwyuhd1#
这个答案完全是“猜测”。只有意法半导体能给予这个宏的原因。但我认为我的理论是可信的,它不适合在一个评论。
首先要注意的是,STM32微处理器具有非常灵活的时钟控制。它完全有可能以160MHz的速度运行CPU,以1MHz的速度运行外围总线。
随机选择我最近使用的STM32,STM32L4P5,您可以查看reference manual的第6.2.18节,其中谈到启用外围时钟...
使能位具有同步机制,可为外设创建无毛刺时钟。使能位置位后,在时钟激活前有2个时钟周期延迟
因此,使能外设时钟后,需要等待2个周期,时钟才会激活。但这不是CPU时钟的2个周期,而是外围时钟的2个周期。
因此,宏不能通过执行一些
NOP
指令来延迟2个周期。它必须在外围总线(可能慢得多)上延迟周期。这种强制读取(通过易失性指针)可以实现这一点。r7knjye22#
SET_BIT(RCC-〉IOPENR,RCC_IOPENR_GPIOAEN);,其余的似乎只是无用的膨胀。
不,不是的。
SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);
使能时钟tmpreg = READ_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);
STM32 uC中外围总线上的操作是强有序的,因此当写操作完成时,读操作将开始。此外,此读取为GPIO时钟建立提供了足够的时间。UNUSED(tmpreg);
正在关闭编译器关于未使用变量的警告。这是一种相当保守的方式(不是错误的方式)。可以通过简单的
UNUSED(RCC->IOPENR);
来避免volatile
变量。此操作也将花费2个以上的周期,并且不会被编译器优化,因为IOPENR
被声明为volatile
https://godbolt.org/z/MnPK9v37v
请记住,回读在非强排序的总线上不起作用。在这种情况下,可以在写入完成之前完成读取。