我正在学习如何使用寄存器对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*)(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 0x4002000
#define ODR_OFFSET 0x14
#define GPIO_ODR (*(volatile uint32_t *)(GPIOA + ODR_OFFSET))
为什么#define
不是指针?它对编译器更友好,并且节省了一次读取的内存。
#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
强制转换应在常量值之外,换句话说,您要添加GPIOA地址+ 14以生成新地址。所以演员必须在他们外面:
GPIOA_ODR = (uint32_t*)(GPIOA + 0x14);