【问题标题】:STM32 - Pointers and sumSTM32 - 指针和求和
【发布时间】:2020-08-03 05:34:02
【问题描述】:

我正在学习如何使用寄存器对 STM32 Nucleo F446RE 板进行编程。

要知道寄存器的位置,我从数据表中获取边界地址和偏移量。 但是,我无法计算它们的总和。我举个例子:

volatile uint32_t *GPIOA = 0x0; // Initialization of the boundary adress
GPIOA = (uint32_t*)0x40020000; // Boundary adress from datasheet

volatile uint32_t *GPIOA_ODR = 0x0; // Initialization of GPIOA_ODR register
GPIOA_ODR = GPIOA +  (uint32_t*)0x14; // Calculation of GPIOA_ODR as the sum of the boundary adress and the offset (i.e. 0x14.

第5行给我一个错误,你知道如何正确计算吗?

非常感谢您。

【问题讨论】:

  • 你的演员阵容错了!。正确的演员表可以写成GPIOA_ODR = (uint32_t*)(GPIOA + 0x14);
  • 方式不对。 IMO 对你来说太早了。你需要先学习指针和指针运算。使用来自 stm 标头的定义。它们的定义正确。
  • @lheb Albouda 它不起作用。这是我尝试过的一种解决方案,但没有。

标签: c pointers stm32 offset cpu-registers


【解决方案1】:

这是错误的。如果你想用这种极其不方便的方式:

#define GPIOA 0x4002000
#define ODR_OFFSET 0x14

#define GPIO_ODR (*(volatile uint32_t *)(GPIOA + ODR_OFFSET))

为什么#define 不是指针?它只是对编译器更友好,并且节省了一次内存读取。

https://godbolt.org/z/LdLLVN

#define GPIOA 0x4002000
#define ODR_OFFSET 0x14

#define GPIO_ODR (*(volatile uint32_t *)(GPIOA + ODR_OFFSET))

volatile uint32_t *pGPIO_ODR = (volatile uint32_t *)(GPIOA + ODR_OFFSET);

void foo(uint32_t x)
{
    GPIO_ODR = x;
}

void bar(uint32_t x)
{
    *pGPIO_ODR = x;
}

以及生成的代码

foo:
        ldr     r3, .L3
        str     r0, [r3, #20]
        bx      lr
.L3:
        .word   67117056
bar:
        ldr     r3, .L6
        ldr     r3, [r3]
        str     r0, [r3]
        bx      lr
.L6:
        .word   .LANCHOR0
pGPIO_ODR:
        .word   67117076

【讨论】:

    【解决方案2】:

    我试过了,但没有。如果我插入 GPIOA_ODR = (uint32_t*)(0x40020000 + 0x14); 它可以工作,而不是如果我插入 GPIOA_ODR = (uint32_t*)(GPIOA + 0x14); 它不起作用。 其他想法?

    非常感谢您的回答。我使用的完整代码如下:

    int main(int argc, char* argv[])
    {
        /** RCC **/
        /* RCC */
        volatile uint32_t *RCC = 0x0;
        RCC = (uint32_t*)0x40023800;
        /* RCC_AHB1ENR */
        volatile uint32_t *RCC_AHB1ENR = 0x0;
        RCC_AHB1ENR = (uint32_t*)(0x40023800 + 0x30);
        *RCC_AHB1ENR |= 0x1;
    
        /** GPIOA **/
        /* GPIOA */
        volatile uint32_t *GPIOA = 0x0;
        GPIOA = (uint32_t*)0x40020000;
        /* GPIOA_MODER */
        volatile uint32_t *GPIOA_MODER = 0x0;
        GPIOA_MODER = (uint32_t*)(0x40020000 + 0x00);
        *GPIOA_MODER |= 1 << 16;
        *GPIOA_MODER &= ~(0 << 17);
        /* GPIOA_ODR */
        volatile uint32_t *GPIOA_ODR = 0x0;
        GPIOA_ODR = (uint32_t*)(GPIOA + 0x14);
        *GPIOA_ODR |= 1 << 8;
    }
    

    由于GPIOA_ODR = (uint32_t*)(GPIOA + 0x14); 行,此代码无法正常工作。如果我插入 GPIOA_ODR = (uint32_t*)(0x40020000 + 0x14) 它可以正常工作。

    【讨论】:

    • 我建议定义每个寄存器。 #define GPIOA 0x40020000你可以在你的主要之前写这个。这使您的代码更具可读性并帮助您避免此类错误。
    • 你需要学习指针。您的代码不起作用,因为您没有仅添加 0x14 字节 0x14 uint32_ts
    【解决方案3】:

    强制转换应该在常量值之外,换句话说,您正在添加 GPIOA 地址 + 14 以生成新地址。所以演员必须在他们之外:

    GPIOA_ODR = (uint32_t*)(GPIOA +  0x14);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-13
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      • 2017-07-19
      相关资源
      最近更新 更多