操作寄存器的正确方法PUT32 vs GPIO->ODR

问题描述

我正在学习如何在没有一堆抽象的情况下使用微控制器。 I've read somewhere 最好使用 PUT32() 和 GET32() 而不是 volatile 指针和其他东西。这是为什么?

使用基本的引脚摆动“基准”,GPIO->ODR=0xFFFFFFFF性能似乎比 PUT32(GPIO_ODR,0xFFFFFFFF) 快四倍,如范围所示:

Port wiggle using PUT32

Port wiggle using GPIO->ODR

(频率较低的是PUT32)

这是我使用 PUT32 的代码

PUT32(0x40021034,0x00000002); // RCC IOPENR B 
PUT32(0x50000400,0x00555555); // PB MODER
while (1) {
    PUT32(0x50000414,0x0000FFFF); // PB ODR
    PUT32(0x50000414,0x00000000); 
}

这是我使用箭头的代码

* (volatile uint32_t *) 0x40021034 = 0x00000002; // RCC IOPENR B 
GPIOB->MODER = 0x00555555; // PB MODER
while (1) {
    GPIOB->ODR = 0x00000000; // PB ODR
    GPIOB->ODR = 0x0000FFFF; 
}

我无耻地从某个地方改编了 PUT32 的程序集

PUT32     PROC
    EXPORT  PUT32     
    STR R1,[R0]
    BX LR
    ENDP

我的问题是:

  • 为什么一种方法看起来像是在做同样的事情时速度会更慢?
  • 与 GPIO 交互的正确或最佳方式是什么? (或者更确切地说,不同方法的优缺点是什么?)

附加信息:

  • 芯片为 STM32G031G8Ux,使用 Keil uVision IDE。
  • 我没有将时钟配置为尽可能快,但两次测试应该保持一致。
  • 这是我的硬件设置:(示波器探头连接到 LED。额外的电线在这里应该不起作用)

Breadboard setup

感谢您的宝贵时间,如有任何误解,敬请谅解

解决方法

PUT32 是一个完全非标准的方法,由另一个问题中的发布者组成。他们这样做是为了避免定义寄存器访问方法时的复杂性和可能的​​错误。

当您使用标准的 CMSIS 头文件并以标准方式分配给寄存器时,所有复杂的问题都已经由对您使用的目标有特定了解的人为您解决。他们的设计方式使您难以犯 PUT32 试图避免的错误,并且使最终语法看起来更清晰。

直接写入寄存器更快的原因是因为写入寄存器只需处理器时钟的一个周期,而调用函数然后写入寄存器然后返回需要四倍的时间实验的背景。

通过使用这种通用访问方法,如果您使用制造商提供的头文件,您还可能会引入错误:例如,当寄存器为 16 位或 8 位时使用 32 位访问。