你能将C ++对象映射到内存映射外设吗?

问题描述 投票:2回答:2

我在过去看过以下技巧:

struct MyStruct
{
   field 1;
   field 2;
   field 3;
};

void f()
{
   MyStruct *example = (memory mapped peripheral address);
}

这基本上使得变量示例现在包含存储器映射的外围设备的地址(值),然后字段1处于相同的偏移,字段2处于(基地址+ sizeof(字段1)),依此类推。

当与外设相关联的多个偏移位于连续内存中时,这很有用,因为它提供了一个抽象层。

我想知道你是否可以对C ++对象做同样的事情,以及如何使这个对象成为单例,继承如何影响这种映射。

c++
2个回答
4
投票

我想知道你是否可以用C ++对象做同样的事情,

是的,同样可以做到。十多年来,我在电信系统开发中使用C ++进行内存映射。我很少处理嵌入式软件中的结构,结构没有优于类。此外,我更喜欢掩盖并转移到处理字段,我对位字段产生了一些厌恶。

对于struct和class实例,可以确定和确认数据布局和打包,因此assert()可以在运行时通知错误地构建数据。

a)C和C ++都不提供内存布局语义

b)编译器选项可以改变结果(打包,对齐,字段重新排列)

这两项需要某种运行时检查。我们通常断言数据属性总长度,以及字段偏移开始之间的一个或多个距离,所有这些都在命名符号中。

许多编译器提供了编译指示来支持内存映射io打包和对齐问题。不幸的是,不同编译器的编译指示通常有不同的名称。这通常并不重要,因为硬件特定的软件几乎从不便携。我遇到的所有pragma似乎都有效。最终我们选择不使用它们。

请注意,字节序也会产生影响,但您使用的硬件将(或者必须)设计为具有正确的字节序。

我拥有使用工具vxWorks的大部分嵌入式系统经验,还有一些使用OSE。两者都在2011年之前使用GCC。

以及如何使这个对象成为单例和

我发现单身人士没有价值。但我相信单例可以用传统方式构建,因为实例的代码不存储在数据字段中。它们是分开的。当你调用你的singletonGet()方法时,它需要将数据'out'映射到hw地址。

“如何在地址0xAAAA0001处寻址hw”的最典型机制是将uint64_t枚举地址强制转换为指针

 class FooHW; // hardware class

 FooHW* foo = reinterpret_cast<FooHW*>(AAAA0001_uint64_t); // enum addr

这会跳过所有ctor / dtor的东西。这是可取的。如何访问内存映射设备通常不得在软件重启期间干扰操作hw。热启动(其中hw已经运行,但软件已经重新启动)在开发和运行期间比冷启动(也称为电源反弹)更为常见。

可以使用放置'new'(和'delete')在正确的内存地址创建实例。但这没有任何优势。您应该研究冷启动,热启动,保护开关等。与其余代码一起使用的Foo *指针是典型的。

遗产将如何影响这种映射。

我想所有这些问题都是特定于工具的。我所看到的是基类数据属性预先设置为派生类数据属性。有些工具可能反过来做。

在我的工作中,我不记得要派生的内存映射实例。但是,我认为它可以起作用,我会选择避免更多的努力。


1
投票

你根本不需要让它成为单身人士。通过你正在使用的技术,你总是会指向同一个地址。无论您使用哪个指针变量到达那里,只要它包含正确的地址。

语法如下所示:

#define DEV_REG_SET (*(volatile MyStruct *)(0x4CF3217))

其中0x4CF3217是您的特殊设备地址,您可以使用它

long f1 = DEV_REG_SET->field1;  // to read from device

你绝对需要将指针声明为指向易失性事物的指针。这将确保编译器始终读取和写入指向的内容,并且不会优化读取和写入。

有关volatile以及如何正确使用see this blog post "Nine ways to break your systems code using volatile"的精彩讨论。

请注意,我发现博客帖子声称某些编译器在应用于结构字段时可能会或可能不会正确地尊重volatile关键字。但我还没有在网上看到任何编译器不会在指向struct的指针上遵守volatile的任何内容。但是你永远都不知道,所以在提交之前先看一下生成的机器语言(如果你得到的时髦结果,请记得检查它)。

现在,关于继承 - 只要你远离编译器将隐藏数据添加到结构的任何东西,你就可以了。但无论如何你知道。毕竟,您已经知道必须确保理解编译器可能执行的所有填充。因此,您必须远离拥有任何虚拟方法或虚拟继承,并且需要避免访问说明符(这可能会影响字段顺序)。换句话说,坚持使用POD - 普通旧(C)数据结构。

© www.soinside.com 2019 - 2024. All rights reserved.