gpt4 book ai didi

c++ - 通过结构访问ARM外设寄存器

转载 作者:行者123 更新时间:2023-12-01 14:42:28 25 4
gpt4 key购买 nike

我想为支持ARM Cortex-M3的设备创建自己的库。当前写入寄存器如下所示:

(*((unsigned int volatile * const)(0x400E0410))) = (1 << 11) | (1 << 12);
其中 0x400E0410是32位外围设备寄存器的地址(在这种情况下,电源管理 Controller 的“外围时钟使能寄存器”的地址)。
因此,我希望将外围设备抽象为 struct,以使其更加用户友好,易读,并允许在IDE内部自动完成。然后,前面的示例将如下所示:
PMC.PCER = PORTB.ID | PORTC.ID;
我不能在 volatile或其成员上使用 struct,否则(据我所知)始终会在最终代码中包含该结构,即使该代码实际上并未用于任何内容。我还注意到,即使该结构是 name-less且其所有成员都已初始化为const值,编译器也会为其构造一个构造函数并将其存储在RAM中,而不是真正次优的FLASH中。
理想情况下,我还希望 struct方法生成这样的汇编代码(第一个示例的反汇编):
first example disassembly
而不是从RAM中读取结构变量的此类代码(我在结构内部使用易失成员的方法):
second example disassembly
如何在不影响程序大小或性能的情况下实现这一目标?
编辑:我的方法的C++代码,u32v是一个无符号的volatile 32位整数,u32c是一个无符号的const 32位整数
my code

最佳答案

So I wish to abstract peripherals into struct so it's a lot more user-friendly ...


许多“MCAL”数据包(汽车行业中使用的硬件抽象)就是这样做的。例:
typedef struct {
unsigned IN; /* offset 0 */
unsigned _unused1[3];
unsigned OUT; /* offset 0x10 */
unsigned _unused2[3];
unsigned DIR; /* offset 0x20 */
} PortStruct;

#define PORTA (*(volatile PortStruct *)0x80001000))
#define PORTB (*(volatile PortStruct *)0x80002000))
...因此您可以通过以下方式访问外设寄存器:
PORTA.OUT |= (1<<4);
我还看到这样的结构已被声明为变量:
extern volatile PortStruct PORTA;
...,并且在链接器配置文件中使用编译器特定的关键字,手写的汇编代码或特殊指令,在固定地址(示例中为0x80001000)处定义了“变量”。

I can't use volatile ... on its members


似乎有些编译器甚至不允许成员使用 volatile,而只允许整个 struct

... the compiler makes a constructor for it and stores it in RAM instead of the FLASH which is really suboptimal.


您使用这些 struct的方式对我来说有点奇怪。
我刚刚使用用于ARM的GCC工具链(C,不是C++)尝试了以下代码,并启用了优化功能:
typedef struct {
unsigned hello;
unsigned world;
unsigned foo;
unsigned bar;
unsigned PCER;
unsigned example;
} PortType;

#define PMC (*(volatile PortType *)0x400E0400)

void test(void)
{
PMC.PCER = 5;
}
结果(这里是目标文件):
00000000 <test>:
0: 4b01 ldr r3, [pc, #4] ; (8 <test+0x8>)
2: 2205 movs r2, #5
4: 611a str r2, [r3, #16]
6: 4770 bx lr
8: 400e0400 .word 0x400e0400
没有生成初始化代码,构造函数或类似代码。
我还尝试了 extern volatile PortStruct方法:
typedef struct {
...
} PortType;

extern volatile PortType PMC;

void test(void)
{
PMC.PCER = 5;
}
正如已经写的,链接脚本中的某些手写汇编代码和某些信息对于将伪变量“PMC”的地址定义为0x400E0400是必要的。
我尝试了两种方法(汇编和链接脚本):结果与 #define方法完全相同。
编辑
我还使用C++编译器而不是C编译器来编译代码:结果代码相同。

关于c++ - 通过结构访问ARM外设寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62905887/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com