【发布时间】:2015-09-28 03:11:42
【问题描述】:
带有 Cortex M3 MCU(STM32F1) 的嵌入式设备。它具有嵌入式闪存(64K)。 MCU固件可以在运行时重新编程闪存扇区;这是由闪存控制器(FMC)寄存器完成的(所以它不像 a=b 那样简单)。 FMC 获取缓冲区指针并将数据烧录到某个闪存扇区。
我想将最后一个闪存扇区用于设备配置参数。 参数存储在带有数组的打包结构中,并包含一些自定义类。
可以在运行时更改参数(复制到 RAM,使用 FMC 更改并烧回闪存)。
所以有一些问题:
参数结构的状态(按位)由 FMC 硬件更改。 C++ 编译器不知道它是否已更改。 这是否意味着我应该将所有结构成员声明为 volatile? 我认为是的。
-
Struct 应该在编译时静态初始化(默认参数)。结构应该是 POD(TriviallyCopyable 并且具有标准布局)。请记住,那里有一些自定义类,所以我记住这些类也应该是 POD。 但是有一些问题: cppreference.com
唯一可平凡复制的类型是标量类型,可平凡复制 类和此类类型/类的数组(可能是 const 限定的, 但不是 volatile 限定的)。
这意味着我不能同时保持我的类 POD 和 volatile? 那么我该如何解决这个问题呢?
可以在参数结构中只使用标量类型,但这可能会导致配置处理的代码更不干净...
附言 即使没有 volatile,它也可以工作,但恐怕有一天,一些智能 LTO 编译器会看到静态初始化,而不是更改(通过 C++)结构并优化对底层内存地址的一些访问。这意味着不会应用新的编程参数,因为它们已被编译器内联。
编辑: 不使用 volatile 也可以解决问题。而且似乎更正确。
您需要在单独的翻译单元(.cpp 文件)中定义配置结构变量,并且不要初始化变量以避免在 LTO 期间替换值。如果不使用 LTO - 一切都可以,因为一次在一个翻译单元中进行优化,因此不应优化具有静态存储持续时间和在专用翻译单元中定义的外部链接的变量。只有 LTO 可以在不发出内存提取的情况下将其丢弃或进行值替换。特别是在将变量定义为 const 时。如果不使用 LTO,我认为初始化变量是可以的。
【问题讨论】:
-
但是,易失性内存不是普通的旧数据。它是读取和写入是可观察行为的数据。在普通的旧数据中,跳过或读取或写入结构成员之间的“填充”没有(定义的)副作用。在易失性内存中,这样的读/写可能不是?为什么需要您的数据成为 POD?
-
为什么不将闪存中的数据 memcpy 到您的 POD 中?
-
>为什么不将闪存中的数据 memcpy 到您的 POD 中?我没有足够的 RAM 在运行时这样做。我希望在程序中某处需要配置数据时直接从闪存中读取它们。当我有 RAM 并且可以重新刷新配置时,我有特殊的配置模式。我认为配置结构应该是 POD,因为这样我就可以在配置模式下使用 memcpy。我也可以静态初始化结构,这非常重要,因为动态初始化不能应用于闪存。可能是我没有清楚地理解易失性的含义。基本上我害怕优化闪存读数,就像我在 P.S 中所说的那样
-
请记住,必须告诉闪存控制器对闪存进行编程。 FMC 不会自行对闪存进行编程。
-
对闪存的编程只是在操作 FMC 硬件寄存器(从 C++ 编译器的角度来看)。 FMC 寄存器修改不能被视为配置结构修改。 IE。 FMC 工作并不意味着配置结构的“可观察行为”。这就是我要说的。
标签: c++ c++11 arm embedded stm32