嵌入式 C++11 代码 — 我需要 volatile 吗?

2024-02-19

采用 Cortex M3 MCU(STM32F1) 的嵌入式设备。它具有嵌入式闪存(64K)。 MCU固件可以在运行时重新编程闪存扇区;这是由闪存控制器(FMC)寄存器完成的(所以它不像a=b那么简单)。 FMC 获取缓冲区指针并将数据刻录到某个闪存扇区。

我想将最后一个闪存扇区用于设备配置参数。 参数存储在带有数组的打包结构中,并包含一些自定义类。

参数可以在运行时更改(复制到 RAM、使用 FMC 更改并烧回闪存)。

所以有一些问题:

  1. 参数结构的状态(按位)由 FMC 硬件更改。 C++编译器不知道它是否被改变。这是否意味着我应该将所有结构成员声明为易失性?我想是的。

  2. 结构体应该在编译时静态初始化(默认参数)。结构应该是POD(TriviallyCopyable并且具有标准布局)。请记住,其中有一些自定义类,因此我记住这些类也应该是 POD。 但也存在一些问题:cppreference.com http://en.cppreference.com/w/cpp/types/is_trivially_copyable

    唯一可平凡复制的类型是标量类型,可平凡复制 类,以及此类类型/类的数组(可能是 const 限定的,但不具有 挥发性 资格).

这意味着我不能让我的课程同时保持 POD 和易失性?那么我该如何解决这个问题呢?

可以在参数结构中仅使用标量类型,但这可能会导致配置处理周围的代码不那么干净......

P.S.即使没有 volatile,它也能工作,但我担心有一天,一些智能 LTO 编译器会看到静态初始化,而不是更改(通过 C++)结构,并优化对底层内存地址的一些访问。这意味着新编程的参数将不会被应用,因为它们是由编译器内联的。

EDIT:不使用 volatile 也可以解决问题。而且似乎更正确。

您需要在单独的翻译单元(.cpp 文件)中定义配置结构变量,并且不要初始化变量以避免在 LTO 期间进行值替换。如果不使用 LTO - 一切都可以,因为优化一次在一个翻译单元中完成,因此具有静态存储持续时间和在专用翻译单元中定义的外部链接的变量不应被优化掉。只有 LTO 可以丢弃它或进行值替换而不发出内存获取。特别是当将变量定义为 const 时。我认为如果不使用LTO,初始化变量是可以的。


根据您的编译器,您有一些选择:

  • 您可以声明一个指向该结构的指针并初始化该指针 到该地区。
  • 告诉编译器变量应该驻留在哪里

指向闪存的指针

声明结构的指针。
将指针分配给 Flash 中的正确地址。
通过取消引用指针来访问变量。
该指针应该被声明和分配为指向常量数据的常量指针。

告诉编译器变量的地址。

某些编译器允许您将变量放置在特定的内存区域中。第一步是在链接器命令文件中创建一个区域。下一步是告诉编译器该变量位于该区域中。

同样,该变量应声明为“static const”。 “静态”是因为只有 1 个实例。 “const”是因为闪存在大多数情况下是只读的。

闪存:易失性与常量

在大多数情况下,闪存无论如何编程,都是只读的。事实上,读取闪存中数据的唯一方法就是锁定它,即使其只读。一般情况下,未经程序一致同意,不会更改。

大多数闪存都是由软件编程的。通常,这是您的程序。如果您的程序要重新编程闪存,它就会知道值已更改。这类似于写入 RAM。这program改变的是价值,而不是硬件。因此Flash是not易挥发的。

我的经验是,Flash 可以通过其他方式进行编程,通常是在程序未运行时。在这种情况下,它仍然不是易失性的,因为您的程序没有运行。 Flash 仍然是只读的。

当且仅当您的执行线程处于活动状态时另一个任务或执行线程对闪存进行编程时,闪存才会是易失性的。我仍然不认为这个案子是volatile。这将是同步性的一个例子——如果 flash 被修改,那么应该通知一些监听器。

Summary

闪存最好被视为只读存储器。尽管某些编译器和链接器允许您在特定的硬编码地址声明变量,但通过指针访问驻留在 Flash 中的变量以获得最佳可移植性。变量应声明为const static以便编译器可以发出代码来直接访问变量,而不是在堆栈上复制。如果闪存由另一个任务或执行线程编程,则这是同步问题,而不是以下问题之一:volatile。在极少数情况下,在执行程序时,闪存会由外部源进行编程。

您的程序应该提供校验和或其他方法来确定自上次检查以来内容是否已更改。

不要让编译器从闪存初始化变量。
这并不是真正的便携。更好的方法是让初始化代码从闪存加载变量。让编译器从不同的段加载变量需要对编译器和链接器的内部进行大量工作;不仅仅是初始化指向闪存中地址的指针。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式 C++11 代码 — 我需要 volatile 吗? 的相关文章

随机推荐

  • Linux下如何用C写文件?

    我想重写Linux的 cp 命令 所以这个程序会像这样工作 a out originalfile copiedfile 我可以打开文件 创建新文件 但无法写入新文件 什么也没写 可能是什么原因 当前的C代码是 include
  • 无法将类型“TEnum”转换为“int”

    我正在尝试将枚举转换为列表 如中所述this https stackoverflow com questions 3489453 how can i convert an enumeration into a listselectlisti
  • 降低 jquery UI 中手风琴的速度

    我对这段代码有两个问题 首先我想降低效果的速度 其次 就像您对效果进行操作以关闭选项卡一样 然后将出现以下新选项卡 if sidebar ul length sidebar ul accordion event mouseover acti
  • 从 SQLite 中的 INSERT OR IGNORE 语句查找自动递增值

    我有一个名为 图像 的表 CREATE TABLE images id INTEGER PRIMARY KEY AUTOINCREMENT url TEXT NOT NULL UNIQUE caption TEXT 插入行时 我希望 URL
  • `npm install` 和 `npmaudit` 计数之间的区别?

    最近添加后npm audit 用于审核依赖关系 我注意到有多少个包之间存在巨大差异added 安装在node modules 以及有多少个audited by npm 这是一个例子 这是我的问题 我说得对吗281已安装的软件包总数是多少 W
  • Selenium 单击与文本对应的 JavaScript 按钮

    我的网页中有很多按钮 它们也是 javascript 按钮 所有这些按钮都有相同的 TagName 但 id 不同 但我不能使用 ID 因为我无法预测必须单击哪个按钮 Selenium 将搜索内容 问题here https stackove
  • 在网络上创建电子邮件表单时的安全注意事项

    我知道我必须考虑 邮件头注入 还有更多的事情吗在发送表格邮件之前我需要知道吗 我想要邮件 我觉得我必须设置表单邮件在我的页面上 但我听说邮件事情很危险 如果我 不考虑所有安全问题 1 避免垃圾邮件 使用验证码或其他东西来防止垃圾邮件 链接谈
  • 返回位于本地堆栈上的块

    clang 分析器可以检查返回的基于堆栈的内存 dispatch block t getPrintBlock const char msg return printf s msg 引发此错误 returning block that liv
  • 无法在 iOS8 上设置交互式推送通知

    我已经能够设置交互式本地通知 但远程通知不起作用 我正在使用 Parse com 发送 JSON 我的 AppDelegate Swift 看起来像这样 AppDelegate swift SwifferApp Created by Tra
  • knitr 中 python 块的根目录?

    我希望这并不像我感觉的那么简单 我已经设置了一个基本目录 root gt Paper gt Code 对于我正在写的一篇论文 我想从 Paper 目录中的knitr 文档调用 Code 目录中的 Python 脚本 类似于this http
  • Pandas:如何将列中的多个列表拆分为多行?

    我有一只熊猫DataFrame看起来像下面这样 bus uid bus type type obj uid 0 biomass DEB31 biomass output Simple 139804698384200 0 biomass DE
  • 是否可以在 docker 构建期间挂载 tmpfs?

    我目前正在构建包含交叉编译器的容器 由于这些必须在构建阶段构建 如果我可以使用 tmpfs 来实现这一点 那将非常有用 因为一旦安装了各种软件包 构建目录将毫无意义 有什么方法可以说服 docker 在构建时挂载 tmpfs 分区吗 Non
  • 打开的设备太多[重复]

    这个问题在这里已经有答案了 我试图将许多图表写入一个位置 但它却写入了一堆空白图片 我的代码如下所示 titleplot lt NULL for i in 1 99 titleplot lt colnames data i mypath l
  • 从列表中获取随机元素

    我基本上是在寻找 Ruby 的 Elixir 等价物Array sample http ruby doc org core 2 2 0 Array html sample method 可以让我这样做的东西 list 1 2 3 4 5 6
  • IvyDE + WTP:如何解决 Ivy 库被 WTP 忽略的问题?

    我发现 IvyDE 允许我解决 Web 应用程序的冻结核心版本的突出问题 该版本需要能够从更新库中提取额外的代码 以便它位于 Web 应用程序的类路径上 为了提高开发速度 我发现 在工作区中解析 功能允许 Eclipse 将更新库项目的文件
  • java.lang.NoSuchMethodError:没有接口方法 onTransitionToIdle()V

    请告诉我 我是 Android 测试新手 我一直在尝试修复初始 NavigationView 测试 但收到错误 我只是想打开抽屉并单击菜单以进入新活动 java lang NoSuchMethodError No interface met
  • 如何将 CloudStorageAccount 输入绑定到 Azure Function?

    我的简化代码示例 我在 Visual Studio 2017 中构建了以下简化的 Azure Function 代码 public static class FunctionApp FunctionName MyFunction publi
  • 如何删除内联/内联块元素之间的空格?

    这些之间将有 4 像素宽的空间span要素 span display inline block width 100px background color palevioletred p span Foo span span Bar span
  • Skyfield 轨道与太阳系重力场的整合 - 速度问题

    在下面所示的时间测试中 我发现Skyfield http rhodesmill org skyfield 需要几百微秒到一毫秒才能返回obj at jd position km对于单个时间值jd 但较长时间的增量成本JulianDate对象
  • 嵌入式 C++11 代码 — 我需要 volatile 吗?

    采用 Cortex M3 MCU STM32F1 的嵌入式设备 它具有嵌入式闪存 64K MCU固件可以在运行时重新编程闪存扇区 这是由闪存控制器 FMC 寄存器完成的 所以它不像a b那么简单 FMC 获取缓冲区指针并将数据刻录到某个闪存