0
\$\begingroup\$

I am working with an embedded software in which part of the software(some CONST config values) are reflashable, without modifying the application software. Consider the following code:

const uint32 Reflashable_Variable = 0;

uint32* GetAddr_Reflashable_Variable()
{
   uint32* addr;
   addr = &Reflashable_Variable; //Compiler optimizes this access to the static 
                                 //fixed address of Reflashable_Variable.   
   return addr;
}

The problem is that the address of Reflashable_Variable might vary later in the binary due to the change in size of some other parameters. What is the solution to prevent compiler from already assigning the address, rather to access the actual address of Reflashable_Variable during runtime? The compiler used is windriver Diab for PowerPC.

I have thought about using volatile, is it a good solution? Even if it is, it triggers lot of modifications in other parts of the software, so not the best for me. Is there a different possible approach?

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Volatile means that the value of the variable may be changed by an external source such as an interrupt handler. It does not mean that the address of the variable may change. C does not have a standard way of handling this, you will have to invent your own, possibly using a look-up table in a fixed area of flash. \$\endgroup\$ – Steve G Jun 24 '19 at 15:44
  • \$\begingroup\$ The compiler really isn't "optimizing" access, variables don't exist in the compiled code. You should fix the addresses of these variables (and leave space between them as "reserved") or come up with a different scheme like saving the data in some kind of format that is flexible where the first part holds an address offset table. \$\endgroup\$ – Ron Beyer Jun 24 '19 at 18:04
  • \$\begingroup\$ Some machine code can use relative addressing for both code and data. (The data itself can be addressed as PC-relative in some cases if that matters to you for any reason [downloading driver code that requires driver-local static constants, for example.]) You really should study carefully your machine architecture and your requirements and find the best fitting approach that makes the most of the architecture for your usage. (That's not something I can do for you.) From your description, volatile isn't what you want. \$\endgroup\$ – jonk Jun 24 '19 at 18:12
  • 2
    \$\begingroup\$ Compilers can only know addresses at compile time. If the addresses change later on, you can’t rely on the compiler to know about it! \$\endgroup\$ – user69795 Jun 24 '19 at 19:58
  • 1
    \$\begingroup\$ What good would it be if it did not optimize this? Instead of accessing a hardcoded address directly, it would be storing a hardcoded address into the variable 'addr' and then accessing the address stored in the variable 'addr' - which would still be hardcoded. \$\endgroup\$ – user253751 Jun 25 '19 at 1:27
2
\$\begingroup\$

The problem is that the address of Reflashable_Variable might vary later in the binary due to the change in size of some other parameters

No, that's not a problem. The code generated by the compiler will change as well. This isn't optimization but automatic memory layout.

If your program somehow dynamically shuffles around addresses of variables in run-time, then the only sane solution is: don't do that. The solution for such scenarios, where you have EEPROM/dataflash variables which might change later, is rather to allocate every such variable to a fixed, specific address. This has to be done manually by you, in some non-standard, compiler-specific way. (gcc toolchain has __attribute__((section..., other toolchains have @ 0x1234, other toolchains use #pragma etc etc.)

volatile should be used if the contents of the variable may change, due to the variable being stored in on-chip EEPROM/dataflash. So you probably want to use volatile for that reason.

\$\endgroup\$
10
  • 1
    \$\begingroup\$ I think "part of the software(some CONST config values) are reflashable, without modifying the application software" means that the data is changed and flashed without re-compiling and re-flashing the program. \$\endgroup\$ – JimmyB Jun 26 '19 at 13:28
  • 1
    \$\begingroup\$ @JimmyB Which is fine as long as the variables are allocated at fixed addresses. Then it's your average embedded application with on-chip, memory-mapped EEPROM, simple as that. \$\endgroup\$ – Lundin Jun 26 '19 at 13:34
  • \$\begingroup\$ Or you flash pointers to the data to fixed addresses... \$\endgroup\$ – JimmyB Jun 26 '19 at 13:46
  • \$\begingroup\$ @JimmyB That means the actual address of Reflashable_Variable should be accessed by 'addr = ptr2_Reflashable_Variable;' and ptr2_Reflashable_Variable will be at a fixed location in the reflashable area.? But if I'm not wrong 'ptr2_Reflashable_Variable = &Reflashable_Variable' is still needed and will still allocate the fixed address of Reflashable_Variable, so how will it solve the issue? \$\endgroup\$ – Soju T Varghese Jun 26 '19 at 14:06
  • \$\begingroup\$ @SojuTVarghese Yes, the address (pointer) will have to be stored at some known, fixed address in flash. You can define the pointer's location e.g. via the linker script, which you probably need to do anyway if you need a certain space/location where your updatable variables are put. Then you can either declare the pointer variable(s) to be put where you need it via the 'section' attribute, or just use a cast of the known address: uint32_t* ptr = (uint32_t*)0x1234; \$\endgroup\$ – JimmyB Jun 29 '19 at 4:36
0
\$\begingroup\$

If the data changes structurally, i.e. data types are changed or new fields/variables are added, the semantics of the data change and that must be reflected in changes to the code handling them.

However, if you have changes to arrays (including their length) or data that is opaque to the code or data which describes itself in some way, then that's a common scenario and can be handled much the same way as dynamically allocated memory at runtime.

Contrived Example (font data usually will never be updated, but):

// Structure describing a single glyph of a font for a certain character
typedef struct glyph_data {

  glyph_data_t* next_glyph; // Pointer to next glyph of this font, or null if this is the last glpyh

  char character; // The character which this glyph represents

  int width;
  int height;

  uint8_t bitmap[]; // e.g. width*height greyscale values

} glyph_data_t;


// Pointer to the first glpyh of the "primary font". The pointer itself is updatable as the address of that glyph may change as other (font) data gets updated.
const glyph_data_t* const PRIMARY_FONT __attribute__((section("dynamic_flash_data_entry_point")));

// Pointer to the first glpyh of the "secondary font"
const glyph_data_t* const SECONDARY_FONT __attribute__((section("dynamic_flash_data_entry_point")));


void display_primary_font() {
  glyph_data_t* current_glyph = PRIMARY_FONT;
  do {
    // e.g. display the current glyph's bitmap
    // ...
    current_glyph = current_glyph->next_glyph;
  } while ( current_glyph );
}

Here, the code statically only knows that there are two fonts, PRIMARY_FONT and SECONDARY_FONT. Both fonts may be updated later, so the code uses the pointers at known locations to find the fonts' data. Also, the set of characters supported by a font may be changed, so the font data includes the information how many/which characters are included as a linked list (glyph_data_t* next_glyph). If new characters are added, or existing ones removed, only the data needs to be updated. The code (and binary!) will stay the same.

\$\endgroup\$
7
  • \$\begingroup\$ uint8_t bitmap[0]; This isn't valid C, but a non-standard gcc extension that went obsolete 20 years ago, after the introduction of VLA to the language. Anyway, this whole trick is pointless, since you wouldn't have a font table of arbitrary size in NVM, you would pick a suitable size and roll with it. Most importantly, it doesn't make any sense to store a font table in data flash, which is what this question is about. You would always store it in ordinary flash. It will be far too large to fit in most data flashes anyhow. \$\endgroup\$ – Lundin Jul 2 '19 at 6:28
  • \$\begingroup\$ What's a "data flash" supposed to be? - I feel you still didn't get the point though. I agree that a font's data will likely not be updated in practice, but the principle I show is valid, useful and common. The example is to demonstrate that and how you can have fixed 'entry points' for your configuration data, which are known at compile time, so your code can work with them. As the configuration data changes/grows, the pointers' locations remain fixed while their target is updated. \$\endgroup\$ – JimmyB Jul 2 '19 at 8:37
  • \$\begingroup\$ @Lundin It also shows that, especially when you have arrays, the code can definitely work with the data even when the size changes, so the request of the OP does make sense. \$\endgroup\$ – JimmyB Jul 2 '19 at 8:37
  • \$\begingroup\$ @Lundin This scheme also resembles (runtime) polymorphism in OOP or dynamic linking. At compile time, the addresses of functions/methods simply cannot be known, but the address and structure of the VMT is known and can be used at runtime to call code. \$\endgroup\$ – JimmyB Jul 2 '19 at 8:42
  • \$\begingroup\$ Data flash is the term used for emulated eeprom in MCUs, by using flash with small erase segments. It is pretty much a standard peripheral in any modern MCU. Some manufacturers call it eeprom, others data flash. If you don't know what that is, or if you have never written an eeprom driver, you cannot answer this question. \$\endgroup\$ – Lundin Jul 2 '19 at 9:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.