C++ 嵌入式C++;11代码— ;我需要挥发油吗?

C++ 嵌入式C++;11代码— ;我需要挥发油吗?,c++,c++11,arm,embedded,stm32,C++,C++11,Arm,Embedded,Stm32,带有Cortex M3 MCU(STM32F1)的嵌入式设备。它有嵌入式闪存(64K)。 MCU固件可以在运行时重新编程闪存扇区;这是通过闪存控制器(FMC)寄存器完成的(因此不像a=b那么容易)。FMC获取缓冲区指针并将数据刻录到某个闪存扇区 我想使用最后一个闪存扇区作为设备配置参数。 参数存储在带有数组的压缩结构中,并包含一些自定义类 参数可以在运行时更改(复制到RAM,使用FMC更改并烧回闪存)。 因此有一些问题: 参数结构的状态(按位)由FMC硬件更改。 C++编译器不知道它是否被改变。

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

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

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

因此有一些问题:

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

  • 结构应该在编译时静态初始化(默认参数)。结构应该是POD(可复制且具有标准布局)。记住,这里有一些自定义类,所以我要记住这些类也应该是POD。 但也存在一些问题:

    唯一可复制的类型是可复制的标量类型 类以及此类类型/类的数组(可能是const-qualified, 但不合格

  • 这意味着我不能让我的班级同时保持POD和volatile? 那么我该如何解决这个问题呢

    在parameters struct中只使用标量类型是可能的,但这可能会导致配置处理周围的代码不够干净

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

    编辑:不使用volatile就可以解决问题。这似乎更正确


    您需要在单独的转换单元(.cpp文件)中定义config struct变量,并且不要初始化变量以避免LTO期间的值替换。如果不使用LTO-所有都可以,因为优化一次在一个翻译单元中完成,所以不应该优化具有静态存储持续时间和专用翻译单元中定义的外部链接的变量。只有LTO可以将其丢弃或进行值替换,而无需执行内存获取。尤其是将变量定义为常量时。如果不使用LTO,我认为初始化变量是可以的。

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

    • 您可以声明指向该结构的指针并初始化该指针 到该地区
    • 告诉编译器变量应该驻留在哪里
    指向Flash的指针 声明结构的指针。
    将指针分配到闪存中的正确地址。
    通过取消引用指针来访问变量。
    指针应该作为指向常量数据的常量指针进行声明和赋值

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

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

    闪存:易失性与常量 在大多数情况下,闪存无论如何编程,都是只读的。事实上,在Flash中读取数据的唯一方法是将其锁定,即使其成为只读。一般来说,未经计划同意,不得更改

    大多数闪存由软件编程。通常,这是您的程序。如果您的程序要重新编程闪存,它知道值已更改。这类似于给RAM写东西。程序改变了值,而不是硬件。因此,闪光灯不易挥发

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

    当且仅当另一个任务或执行线程在您的执行线程处于活动状态时对闪存进行编程时,闪存才会不稳定。我仍然不认为这种情况是不稳定的。syncronicity就是这种情况——如果修改了flash,那么应该通知一些侦听器

    总结 闪存最好作为只读存储器处理。虽然某些编译器和链接器允许您在特定的硬编码地址声明变量,但闪存中的变量是通过指针访问的,以实现最佳的可移植性。变量应声明为
    const static
    ,以便编译器可以发出代码直接访问变量,而不是在堆栈上复制。如果闪存由另一个任务或执行线程编程,这是一个同步性问题,而不是易失性问题。在极少数情况下,在执行程序时,闪存由外部源编程

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

    不要让编译器从FLASH初始化变量。

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

    通过重新编程flash,可以更改底层对象的表示。
    volat
    
    // Header file
    struct Settings { ... };
    extern const volatile Settings& settings;
    
    // Source file
    static const Settings init_settings = { ... };
    const volatile Settings& settings = init_settings;