C语言 Stm32膨胀或devine知识

uqjltbpv  于 2023-05-06  发布在  其他
关注(0)|答案(2)|浏览(120)

我并不是想发起一场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 */
1tuwyuhd

1tuwyuhd1#

这个答案完全是“猜测”。只有意法半导体能给予这个宏的原因。但我认为我的理论是可信的,它不适合在一个评论。
首先要注意的是,STM32微处理器具有非常灵活的时钟控制。它完全有可能以160MHz的速度运行CPU,以1MHz的速度运行外围总线。
随机选择我最近使用的STM32,STM32L4P5,您可以查看reference manual的第6.2.18节,其中谈到启用外围时钟...
使能位具有同步机制,可为外设创建无毛刺时钟。使能位置位后,在时钟激活前有2个时钟周期延迟
因此,使能外设时钟后,需要等待2个周期,时钟才会激活。但这不是CPU时钟的2个周期,而是外围时钟的2个周期。
因此,宏不能通过执行一些NOP指令来延迟2个周期。它必须在外围总线(可能慢得多)上延迟周期。这种强制读取(通过易失性指针)可以实现这一点。

r7knjye2

r7knjye22#

SET_BIT(RCC-〉IOPENR,RCC_IOPENR_GPIOAEN);,其余的似乎只是无用的膨胀。
不,不是的。

  1. SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN);使能时钟
  2. tmpreg = READ_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN); STM32 uC中外围总线上的操作是强有序的,因此当写操作完成时,读操作将开始。此外,此读取为GPIO时钟建立提供了足够的时间。
  3. UNUSED(tmpreg);正在关闭编译器关于未使用变量的警告。
    这是一种相当保守的方式(不是错误的方式)。可以通过简单的UNUSED(RCC->IOPENR);来避免volatile变量。此操作也将花费2个以上的周期,并且不会被编译器优化,因为IOPENR被声明为volatile
    https://godbolt.org/z/MnPK9v37v
    请记住,回读在非强排序的总线上不起作用。在这种情况下,可以在写入完成之前完成读取。

相关问题