C ++ 11 Embeddable Code - Do I Need Volatility?

Embedded device with Cortex M3 MCU (STM32F1). It has a built-in flash (64K). MCU firmware can flash flash sectors at runtime; this is done using the flash controller registers (FMC) (so it's not as simple as a = b). FMC receives a buffer pointer and writes data to any sector of the flash memory.

I want to use the last sector of the flash memory for device configuration settings. Parameters are stored in a packed structure with arrays and contain some custom classes.

Parameters can be changed at runtime (copy to RAM, change and write back to flash using FMC).

So there are some questions:

  • The state (bitwise) of the struct parameters is changed by the FMC hardware. The C ++ compiler does not know if it has been changed or not. Does this mean that I should declare all elements of the structure unstable? I think yes.

  • At compile time, Static must be statically initialized (default parameters). Struct must be a POD (TriviallyCopyable and has a standard layout). Remember that there are some custom classes, so I remember that these classes must also be POD. BUT there are some problems: cppreference.com

    The only trivially copied types are scalar types, trivially copied classes and arrays of such types / classes (possibly const-qualified , but not volatile-qualified ).

Does this mean that I cannot keep the POD class unstable? So how can I solve the problem?

Only scalar types can be used in struct parameters, but this can lead to much less clean code when processing the configuration ...

PS It works even without variability, but I'm afraid that someday some smart LTO compiler will see a static initialized structure that does not change (in C ++) and optimizes some access to the base memory addresses. This means that the new programmed parameters will not be applied because they were built into the compiler.

EDIT: You can solve the problem without using mutable mode. And that seems more correct.

You need to define the configure configuration variable in a separate translation unit (.cpp file) and not initialize the variable to avoid overriding values ​​during LTO. If you do not use LTO, everything will be fine, because the optimization is performed in one translation unit at a time, so the variables with static storage time and external communication defined in the selected translation block should not be optimized. Only LTO can throw it away or make a replacement of values ​​without issuing memory extracts. Especially when defining a variable as const. I think it's ok to initialize a variable if not using LTO.

+5
source share
2 answers

You have a choice depending on your compiler:

  • You can declare a pointer to a structure and initialize a pointer to a region.
  • Tell the compiler where the variable should be

Flash Pointer

Declare a structure pointer.
Assign a pointer to the correct address in Flash.
Access to variables by dereferencing a pointer.
A pointer must be declared and assigned as a constant pointer to persistent data.

Specifies the address of the variable compiler.

Some compilers allow you to put a variable in a specific area of ​​memory. The first step is to create a region in the linker command file. The next step is to tell the compiler that the variable is in this region.

Again, the variable should be declared as a "static constant". "Static" because there is only one instance. "Const" because flash memory is read-only for most of the time.

Flash Memory: Volatile or Const

In most cases, flash memory, however, is programmed, read-only. In fact, the only way to read data in Flash is to block it, aka make it read-only. In general, it will not be changed without consensus of the program.

Most flash memories are programmed by software. This is usually your program. If your program is about to reprogram Flash, it knows that the values ​​have been changed. This is similar to writing to RAM. The program changed the value, not the hardware. Therefore, Flash is not volatile.

My experience is that Flash can be programmed in a different way, usually when your program is not running. In this case, it is still unstable because your program does not work. The flash is still read-only.

A flash will be volatile if and only if another task or thread of executable programs starts while your thread is executing. I still do not consider this case unstable. This will be a case of synchronization - if the flash is changed, then some listeners should be notified.

Summary

Flash memory is best viewed as read-only memory. Variables in Flash are accessible via a pointer for better portability, although some compilers and linkers allow you to declare variables at certain hard-coded addresses. Variables must be declared as const static so that the compiler can emit code for direct access to the variables, as well as for copying onto the stack. If Flash is programmed by another task or thread of execution, this is a synchronization problem, not a mutable one. In rare cases, Flash is programmed by an external source during the execution of your program.

Your program should provide checksums or other methods to determine if the content has changed since the last time it was checked.

DO NOT USE THE INITIALIZING CONNECTION OF VARIABLES FROM FLASH.
It is not very portable. It is best for your initialization code to load a variable from a flash drive. Creating a compiler to load a variable from another segment requires a lot of work with the internal components of the compiler and linker; much more than initializing a pointer to an address in Flash.

+2
source

By reprogramming the flash, you change the representation of the underlying subject. The volatile qualifier is the right solution for situations where data changes are not optimized.

You would like the declaration to be: const volatile Settings settings;

The disadvantage is that volatile prevents the static initialization of your object. This prevents you from using the linker to put the initialized object in the appropriate memory address.

You want the definition to be: const Settings settings = { ... };

Fortunately, you can initialize the const object and access it as const volatile .


 // Header file struct Settings { ... }; extern const volatile Settings& settings; 

 // Source file static const Settings init_settings = { ... }; const volatile Settings& settings = init_settings; 

The init_settings object init_settings statically initialized, but all calls through the settings link are considered mutable.

Note that changing an object defined as const is undefined.

+2
source

All Articles