了解嵌入式 C 中的 I/O 内存位置
Understanding I/O memory location in embedded C
• 声明一个指针,
int *p;
• 将 I/O 内存位置的地址分配给
指针
p = (int*) 0x30610000;
我想访问内存位置 0x30610000
,其中有一个我想配置的寄存器。
我们为什么要强制转换它? p =0x30610000;
不应该指向位置吗?
int *p;
p = (int*) 0x30610000;
方法和实现都不好
- 使用宏(不是指针变量)访问映射到地址 space 的硬件寄存器。这是更有效的方法。
- 使用固定大小的整数。
- 声明寄存器为
volatile
。它们肯定很容易产生副作用 :)
#define REG1 (*(volatile uint32_t *)0x30610000)
和用法:
REG1 = 0x456;
foo(REG1);
大多数外设都有一个以上的寄存器。最好使用结构来访问它们(注意 volatile
关键字所在的位置。不要使整个结构 volatile
):
typedef struct
{
volatile uint32_t DR;
volatile uint32_t CR;
volatile uint32_t SR;
}UART_type;
#define UART1 ((UART_type *)0x45678000)
和用法:
UART1 -> CR = 0x45676;
在 C 语言中,需要强制转换才能使警告静音,因为它是一个 UB(或者可能只是定义为 @Clifford 建议的实现)。即使实现(如 ARM-gcc)以可预测的方式进行 - 它仍会发出警告。
现在,为什么指针对象的效率低于 #define
。这是因为编译器需要更多的指令来检索寄存器的地址。
• 声明一个指针,
int *p;
• 将 I/O 内存位置的地址分配给 指针
p = (int*) 0x30610000;
我想访问内存位置 0x30610000
,其中有一个我想配置的寄存器。
我们为什么要强制转换它? p =0x30610000;
不应该指向位置吗?
int *p;
p = (int*) 0x30610000;
方法和实现都不好
- 使用宏(不是指针变量)访问映射到地址 space 的硬件寄存器。这是更有效的方法。
- 使用固定大小的整数。
- 声明寄存器为
volatile
。它们肯定很容易产生副作用 :)
#define REG1 (*(volatile uint32_t *)0x30610000)
和用法:
REG1 = 0x456;
foo(REG1);
大多数外设都有一个以上的寄存器。最好使用结构来访问它们(注意 volatile
关键字所在的位置。不要使整个结构 volatile
):
typedef struct
{
volatile uint32_t DR;
volatile uint32_t CR;
volatile uint32_t SR;
}UART_type;
#define UART1 ((UART_type *)0x45678000)
和用法:
UART1 -> CR = 0x45676;
在 C 语言中,需要强制转换才能使警告静音,因为它是一个 UB(或者可能只是定义为 @Clifford 建议的实现)。即使实现(如 ARM-gcc)以可预测的方式进行 - 它仍会发出警告。
现在,为什么指针对象的效率低于 #define
。这是因为编译器需要更多的指令来检索寄存器的地址。