EmbeddedRelated.com
Forums

What is your strategy to save non volatile data?

Started by pozz August 11, 2016
On 8/11/2016 3:21 PM, pozz wrote:
> Il 11/08/2016 17:27, Don Y ha scritto: >> On 8/11/2016 7:53 AM, Don Y wrote: >>> On 8/11/2016 7:12 AM, David Brown wrote: >>> >>>> But for the common case of storing a small set of parameters, I usually >>>> work with a struct definition. Along with the parameters in question, I >>>> include a "magic number" for identification, a "parameter structure >>>> version number" (very useful for upgrading the parameter set if a later >>>> version of the firmware uses more parameters), an update serial number, >>>> a CRC check field, and some space reserved for future additional >>>> parameters. >>> >>> To be clear, you are wrapping *all* of your parameters into a single >>> "parameters_to_be_saved" struct. >>> >>> This can work if they are "configuration parameters" -- data that are >>> consulted when setting up the application, restarting it, etc. >>> >>> This is different than trying to "save application/process state" >>> across power outages. In that case, the "state" may be scattered >>> through many variables dispersed in memory. And, more difficult to >>> ensure catching a "consistent" snapshot. >>> >>> I.e., if *this* variable is changed, are there any others whose state >>> must be reconciled *as* it is being preserved? >>> >>> [It's unclear what the OP is addressing] >> >> A more concrete example: >> >> When I'm in the car, > > [...] > > I'm not sure, but I think many piece of code in the car doesn't save anything > in a non volatile memory. The electronics are always power supplied from the > battery, so it is sufficient to have the variables in RAM. > > Indeed when you unplug the battery for a while, all the parameters revert back > to default.
I haven't yet tried that. It would be "unfortunate" as there are *lots* of parameters involved: station presets (AM/FM/XM) -- for two drivers audio/GPS/telephone "favorites" -- for two drivers music/seat/mirror positions -- for two drivers when should the doors lock themselves? what should the remote key fob do? when the driver opens his/her door, how should other doors react? etc. Plus, of course, the engine related settings...
On 08/11/2016 02:35 PM, Don Y wrote:
> On 8/11/2016 9:12 AM, bitrex wrote: >> On 08/11/2016 12:11 PM, bitrex wrote: >>> On 08/11/2016 11:27 AM, Don Y wrote: >>> >>>> OToOH, if I change the volume level of the radio -- or switch to the >>>> disk drive as "audio source" -- that fact is *also* persistent. As is >>>> the point in the song where power was interrupted! When I return to >>>> the >>>> vehicle, I expect it to resume playing "from disk", the particular song >>>> that was playing at the time power was lost *and* at the particular >>>> point! >>> >>> That's a cool idea, but as far as I can recall I've yet to drive any >>> vehicle which actually does this. >>> >>> My car is a 2015 Chevy, and if the vehicle is turned off with a song >>> playing from CD or Bluetooth, on restart it just returns to its initial >>> state. It doesn't even seem to remember which Bluetooth device you had >>> connected, so if you have two of them in the car and the one you were >>> using is the second on the list of paired devices, you have to manually >>> re-select it. >> >> Oh, and on hot days when you start driving after the car has been >> sitting in >> the sun a while, the center console "information display" will >> sometimes crash >> and reboot. > > We walked away from the Nissans (and some other vendor) for similar > reasons: if I can crash the "system" while it's brand new and > under the watchful care of the dealership, what would it be like > "in the wild"?
You can select a submenu on the dash display, along with the trip counter and tire pressure monitor, etc. that will show you the licensing information for whatever open source software they used in the firmware. So that's nice, I guess. It's probably just for something lame like the MP3 decoder, or something.
In article <noipdo$nnv$1@dont-email.me>, david.brown@hesbynett.no 
says...
> > On 11/08/16 16:53, Don Y wrote: > > On 8/11/2016 7:12 AM, David Brown wrote: > > > >> But for the common case of storing a small set of parameters, I usually > >> work with a struct definition. Along with the parameters in question, I > >> include a "magic number" for identification, a "parameter structure > >> version number" (very useful for upgrading the parameter set if a later > >> version of the firmware uses more parameters), an update serial number, > >> a CRC check field, and some space reserved for future additional > >> parameters. > > > > To be clear, you are wrapping *all* of your parameters into a single > > "parameters_to_be_saved" struct. > > > > This can work if they are "configuration parameters" -- data that are > > consulted when setting up the application, restarting it, etc. > > Yes, exactly. I find this to be quite a common situation - but we all > agree that different systems have different requirements and therefore > different "best" solutions.
Whatever method you use on boot-up load a default set into RAM before checking if any blocks/pages/memory areas contain a VALID set of parameters or states or save sets. Often easier to do reads or checksums of blocks then later do a block copy. Failing that temp copy to RAM buffer check its validity and do memcpy to where it is needed. Valid includes not a higher version than current firmware, always add new features to END of struct. Seen that forgotten too many times. Be prepared to erase invalid sets at that stage. However that erase is done even if single location erase. Work with more than one set, get the latest (or latest per user set)
> > This is different than trying to "save application/process state" > > across power outages. In that case, the "state" may be scattered > > through many variables dispersed in memory. And, more difficult to > > ensure catching a "consistent" snapshot. > > > > I.e., if *this* variable is changed, are there any others whose state > > must be reconciled *as* it is being preserved? > > Usually in such cases, it is still easy enough to have everything in one > structure. At its simplest, all those different state variables > scattered around the program can be fields of the one state struct.
Worst case two or three structures or structure tree Basic configuratio pair min Save state pair min Any other type of data set pair min Generally I run same principles on all data sets only load those that are valid to supercede defaults
> > > > [It's unclear what the OP is addressing] > > Indeed.
We rarely do -- Paul Carpenter | paul@pcserviceselectronics.co.uk <http://www.pcserviceselectronics.co.uk/> PC Services <http://www.pcserviceselectronics.co.uk/pi/> Raspberry Pi Add-ons <http://www.pcserviceselectronics.co.uk/fonts/> Timing Diagram Font <http://www.badweb.org.uk/> For those web sites you hate
In article <noitgh$8fa$1@dont-email.me>, pozzugno@gmail.com says...
> > Il 11/08/2016 16:12, David Brown ha scritto: > > I usually > > work with a struct definition. Along with the parameters in question, I > > include a "magic number" for identification, a "parameter structure > > version number" (very useful for upgrading the parameter set if a later > > version of the firmware uses more parameters), an update serial number, > > a CRC check field, and some space reserved for future additional > parameters. > > > > Typically I have a statically allocated struct in ram, and two copies in > > eeprom or flash. On startup, I check both non-volatile copies to see > > which is the latest version (highest serial number) that has a valid > > CRC, and copy that into RAM. If the parameter structure version number > > does not match the current firmware requirements, I upgrade the > parameters. > > > > When I need to save the parameters, I use the oldest of the two NV sets. > > First, I erase it (for eeprom, that's just clearing the magic number). > > Then I copy in most of the data and CRC, leaving the magic number > for last. > > Interesting approach. > > I couldn't understand what is "magic number" for identification purpose. > CRC can be used to check if the saved struct is valid or not, so the > "magic number" is useless for this goal.
You really want to be sure that you have no other problems like hardware fault that addresses wrong area of memory that happens to have a location that appears to give a valid CRC, watch everything fail in a misleading way. Simply could be firmware change and someone has got the save and read address (even internal ones of external devices) wrong due to part of upgrade being different size 'EEPROM'. I have seen some systems fail if the external storage has been fully erased and give wrong configuration for many other reasons.
> Maybe you have more than one struct saved to the non volatile memory, > and the "magic number" identifies the type of the struct? > In this case, I think the physical address where you save the struct > automatically identifies the struct itsel. > Do you have a different "magic number", "serial number", CRC for each > saved struct?
You could use magic numbers that way but I tend to use additional members for expected type and a diff magic number for double check, to avoid different sizes of each struct and misleading CRC appearing 'valid'. Assumption that you have the right data because you think you are only accessing one area of memory especially if external (or even SD Card) can lead to all sorts of confusion. -- Paul Carpenter | paul@pcserviceselectronics.co.uk <http://www.pcserviceselectronics.co.uk/> PC Services <http://www.pcserviceselectronics.co.uk/pi/> Raspberry Pi Add-ons <http://www.pcserviceselectronics.co.uk/fonts/> Timing Diagram Font <http://www.badweb.org.uk/> For those web sites you hate
Il 12/08/2016 00:30, Don Y ha scritto:
> On 8/11/2016 3:17 PM, pozz wrote: > > [much elided] > >> "Everything in one structure" means you have a global (as the scope in C) >> struct definition that is accessed by every piece of code in the >> project, even >> if they are very different section of the project. > > No. It only has to be *effectively* global. > > E.g., you can have a global "update_parameter()" that takes a > "key" (name for a parameter -- this could be a literal string > *or* just a small integer) and a parameter value (or pointer to > a parameter value). Update_parameter() then moves the "value" > into the referenced portion of the "parameters to be saved struct".
You use update_parameter() function to only move the value from the variable in RAM (managed by the module that really uses that variable) in another place in RAM (the struct that will be saved in a persisten way), right? In this case, exactly who call update_parameter() and when?
> In this way, the definition of the struct can remain opaque. > The same sort of "accessor" can be used to retrieve those > parameters from the struct -- without exposing the struct > or the manner in which the individual parameters are "encoded" (!) > in the struct. > > E.g., you can pack a bunch of (potentially unrelated) parameters > into a bitfield within that struct. Data coming *into* it gets > massaged to manipulate the appropriate fields. Likewise for data > coming *out*. > > Finally, because this represents a monitor, of sorts, you can ensure > atomic operations on that "data to be preserved" -- up to and including > an action that automatically saves the struct to persistent store > when power is failing (the rest of the time, "updates" happen to > the "in-RAM" copy of the struct so you don't incur the costs of > updating FLASH more often than necessary) > >> In the past I used this approach with a global struct container: >> /* In one .h file */ >> struct settings_s { >> uint8_t backlight_level; >> enum DisplayTheme theme; >> uint16_t psu_output_voltage_calibration; >> char password[7]; >> ... >> }; >> extern struct settings_s settings; >> >> /* In one .c file */ >> struct settings_s settings; >> >> /* In display module */ >> backligh_set(settings.backlight_level); >> >> Every module that manages one or more persistent parameters should >> know the >> presence of a global settings variable with an exposed type definition >> (struct >> settings_s). >> I think this is a bad approach that increase the coupling between modules >> instead of decreasing it as it should be. >> >> >> >> [It's unclear what the OP is addressing] >> > >> > Indeed. >> >> Mainly I'm interested in saving configuration parameters/settings >> (color theme, >> calibration data, backlight level, and so on). >> They are parameters that are changed by the user not so frequent. > > But, are they changed in a "configuration mode" or, rather, as part > of the normal use of the device? E.g., if I change the time on my > clock, I don't really enter a special "configuration mode" to do so. > Nor if I change the time zone, alarm settings, etc. The clock > continues to *be* a clock while these persistent changes are happening. > > See my other example re: automobile audio system (and, think of the > similar situation for most other "digital appliances" -- your TV > remembers the channel, volume, picture settings, etc. WITHOUT you > ever having to enter "configuration mode") >
On 12/08/16 00:17, pozz wrote:
> Il 11/08/2016 23:07, David Brown ha scritto: >> On 11/08/16 16:53, Don Y wrote: >>> On 8/11/2016 7:12 AM, David Brown wrote: >>> >>>> But for the common case of storing a small set of parameters, I usually >>>> work with a struct definition. Along with the parameters in > question, I >>>> include a "magic number" for identification, a "parameter structure >>>> version number" (very useful for upgrading the parameter set if a later >>>> version of the firmware uses more parameters), an update serial number, >>>> a CRC check field, and some space reserved for future additional >>>> parameters. >>> >>> To be clear, you are wrapping *all* of your parameters into a single >>> "parameters_to_be_saved" struct. >>> >>> This can work if they are "configuration parameters" -- data that are >>> consulted when setting up the application, restarting it, etc. >> >> Yes, exactly. I find this to be quite a common situation - but we all >> agree that different systems have different requirements and therefore >> different "best" solutions. >> >>> >>> This is different than trying to "save application/process state" >>> across power outages. In that case, the "state" may be scattered >>> through many variables dispersed in memory. And, more difficult to >>> ensure catching a "consistent" snapshot. >>> >>> I.e., if *this* variable is changed, are there any others whose state >>> must be reconciled *as* it is being preserved? >> >> Usually in such cases, it is still easy enough to have everything in one >> structure. At its simplest, all those different state variables >> scattered around the program can be fields of the one state struct. > > "Everything in one structure" means you have a global (as the scope in > C) struct definition that is accessed by every piece of code in the > project, even if they are very different section of the project. >
Yes, that is correct. It is still modular, structured and organised - just organised in a different way. It is a simple and clear method, but works best if the code is being written by a single person rather than a team working on the different parts of the program.
> In the past I used this approach with a global struct container: > /* In one .h file */ > struct settings_s { > uint8_t backlight_level; > enum DisplayTheme theme; > uint16_t psu_output_voltage_calibration; > char password[7]; > ... > }; > extern struct settings_s settings; > > /* In one .c file */ > struct settings_s settings; > > /* In display module */ > backligh_set(settings.backlight_level); > > Every module that manages one or more persistent parameters should know > the presence of a global settings variable with an exposed type > definition (struct settings_s). > I think this is a bad approach that increase the coupling between > modules instead of decreasing it as it should be. >
Coupling like this has disadvantages, but it is not necessarily a bad thing. And usually you are going to end up with some sort of coupling anyway - the display module and the settings module have to exchange information here somehow. They either do so directly, or they do so via a third module that co-ordinates the process. Direct coupling can make it easier to follow what is happening, but is most suited to smaller programs than larger ones.
> >>> [It's unclear what the OP is addressing] >> >> Indeed. > > Mainly I'm interested in saving configuration parameters/settings (color > theme, calibration data, backlight level, and so on). > They are parameters that are changed by the user not so frequent. >
On 12/08/16 00:30, Don Y wrote:
> On 8/11/2016 3:17 PM, pozz wrote: > > [much elided] > >> "Everything in one structure" means you have a global (as the scope in C) >> struct definition that is accessed by every piece of code in the >> project, even >> if they are very different section of the project. > > No. It only has to be *effectively* global. > > E.g., you can have a global "update_parameter()" that takes a > "key" (name for a parameter -- this could be a literal string > *or* just a small integer) and a parameter value (or pointer to > a parameter value). Update_parameter() then moves the "value" > into the referenced portion of the "parameters to be saved struct".
First, /don't/ use strings for that sort of thing unless you have no other choice. And don't use arbitrary integers. Use an enum, that is defined in one place. That way you get it right. Your code refers to the parameters using sensible names, rather than numbers, you don't get overlap or gaps (unless you want them, of course), and you can easily change things when you need to. And when one part of your program writes parameter "backgroundColour" and another part reads parameter "backgroundColor", you get a compile-time error rather than weird behaviour at run-time. But passing the data back and forth through functions like "update_parameter" and "get_parameter" is an alternative to accessing the struct directly, and can be easier to manage. It is certainly convenient if you want to trigger automatic saving of parameters.
> > In this way, the definition of the struct can remain opaque. > The same sort of "accessor" can be used to retrieve those > parameters from the struct -- without exposing the struct > or the manner in which the individual parameters are "encoded" (!) > in the struct. >
Yes.
> E.g., you can pack a bunch of (potentially unrelated) parameters > into a bitfield within that struct. Data coming *into* it gets > massaged to manipulate the appropriate fields. Likewise for data > coming *out*.
That sounds like a complication that is unlikely to be worth the effort, but it's possible. In many cases its enough to simply say "all parameters are 32 bits - it's up to the app if this is 4 characters, a float, an integer, etc.".
> > Finally, because this represents a monitor, of sorts, you can ensure > atomic operations on that "data to be preserved" -- up to and including > an action that automatically saves the struct to persistent store > when power is failing (the rest of the time, "updates" happen to > the "in-RAM" copy of the struct so you don't incur the costs of > updating FLASH more often than necessary) >
Also true - it's always important to make sure your data is consistent at all times.
On 12/08/16 00:16, pozz wrote:
> Il 11/08/2016 16:12, David Brown ha scritto:
<snip>
>> I usually >> work with a struct definition. Along with the parameters in question, I >> include a "magic number" for identification, a "parameter structure >> version number" (very useful for upgrading the parameter set if a later >> version of the firmware uses more parameters), an update serial number, >> a CRC check field, and some space reserved for future additional > parameters. >> >> Typically I have a statically allocated struct in ram, and two copies in >> eeprom or flash. On startup, I check both non-volatile copies to see >> which is the latest version (highest serial number) that has a valid >> CRC, and copy that into RAM. If the parameter structure version number >> does not match the current firmware requirements, I upgrade the > parameters. >> >> When I need to save the parameters, I use the oldest of the two NV sets. >> First, I erase it (for eeprom, that's just clearing the magic number). >> Then I copy in most of the data and CRC, leaving the magic number for > last. > > Interesting approach. > > I couldn't understand what is "magic number" for identification purpose. > CRC can be used to check if the saved struct is valid or not, so the > "magic number" is useless for this goal. > > Maybe you have more than one struct saved to the non volatile memory, > and the "magic number" identifies the type of the struct? > In this case, I think the physical address where you save the struct > automatically identifies the struct itsel. > Do you have a different "magic number", "serial number", CRC for each > saved struct?
The "magic number" is to identify that the type of record. Perhaps the system will have more than one possible set of data, or the same board is used for two completely different applications with different parameter sets.
> > Or do you have a dynamic list of structs that could be saved at > different places of non volatile memory (non fixed address)? In this > case, you have a file list somewhere, similar to a FAT table. Maybe you > have implemented a minimal filesystem where a file is a struct. > > >> I have had occasion to use a log structured parameter "file system" in >> flash, but usually such complications are unnecessary. And certainly >> SQLite, or JSON, etc., are normally overkill. >> >
David Brown <david.brown@hesbynett.no> writes:

> On 12/08/16 00:30, Don Y wrote: >> On 8/11/2016 3:17 PM, pozz wrote: >> >> [much elided] >> >>> "Everything in one structure" means you have a global (as the scope in C) >>> struct definition that is accessed by every piece of code in the >>> project, even >>> if they are very different section of the project. >> >> No. It only has to be *effectively* global. >> >> E.g., you can have a global "update_parameter()" that takes a >> "key" (name for a parameter -- this could be a literal string >> *or* just a small integer) and a parameter value (or pointer to >> a parameter value). Update_parameter() then moves the "value" >> into the referenced portion of the "parameters to be saved struct". > > First, /don't/ use strings for that sort of thing unless you have no > other choice. And don't use arbitrary integers. Use an enum, that is > defined in one place. That way you get it right.
But having it all defined in one place is basically the situation you started with, with the global struct. I have tried putting the non-volatiles in a special section, which then gets written out after a change. That avoids the global dependencies but adding a new variable then messes up the ordering and corrupts any stored struct copy. (E.g. a firmware update with new settings). Besides as I think you said usually something needs access to everything anyway, like a UI or diagnostics module.
> Your code refers to > the parameters using sensible names, rather than numbers, you don't get > overlap or gaps (unless you want them, of course), and you can easily > change things when you need to. And when one part of your program > writes parameter "backgroundColour" and another part reads parameter > "backgroundColor", you get a compile-time error rather than weird > behaviour at run-time. > > But passing the data back and forth through functions like > "update_parameter" and "get_parameter" is an alternative to accessing > the struct directly, and can be easier to manage. It is certainly > convenient if you want to trigger automatic saving of parameters.
With the single struct idea I periodically run a checksum to detect a change.
>> >> In this way, the definition of the struct can remain opaque. >> The same sort of "accessor" can be used to retrieve those >> parameters from the struct -- without exposing the struct >> or the manner in which the individual parameters are "encoded" (!) >> in the struct. >> > > Yes. > >> E.g., you can pack a bunch of (potentially unrelated) parameters >> into a bitfield within that struct. Data coming *into* it gets >> massaged to manipulate the appropriate fields. Likewise for data >> coming *out*. > > That sounds like a complication that is unlikely to be worth the effort, > but it's possible. In many cases its enough to simply say "all > parameters are 32 bits - it's up to the app if this is 4 characters, a > float, an integer, etc.". > >> >> Finally, because this represents a monitor, of sorts, you can ensure >> atomic operations on that "data to be preserved" -- up to and including >> an action that automatically saves the struct to persistent store >> when power is failing (the rest of the time, "updates" happen to >> the "in-RAM" copy of the struct so you don't incur the costs of >> updating FLASH more often than necessary) >> > > Also true - it's always important to make sure your data is consistent > at all times. > >
-- John Devereux
On 12/08/16 14:14, John Devereux wrote:
> David Brown <david.brown@hesbynett.no> writes: > >> On 12/08/16 00:30, Don Y wrote: >>> On 8/11/2016 3:17 PM, pozz wrote: >>> >>> [much elided] >>> >>>> "Everything in one structure" means you have a global (as the scope in C) >>>> struct definition that is accessed by every piece of code in the >>>> project, even >>>> if they are very different section of the project. >>> >>> No. It only has to be *effectively* global. >>> >>> E.g., you can have a global "update_parameter()" that takes a >>> "key" (name for a parameter -- this could be a literal string >>> *or* just a small integer) and a parameter value (or pointer to >>> a parameter value). Update_parameter() then moves the "value" >>> into the referenced portion of the "parameters to be saved struct". >> >> First, /don't/ use strings for that sort of thing unless you have no >> other choice. And don't use arbitrary integers. Use an enum, that is >> defined in one place. That way you get it right. > > But having it all defined in one place is basically the situation you > started with, with the global struct.
It is similar, but there is less shared detail. And if it all helps you catch mistakes at compile-time rather than run-time, then it is a good thing.
> > I have tried putting the non-volatiles in a special section, which then > gets written out after a change. That avoids the global dependencies but > adding a new variable then messes up the ordering and corrupts any > stored struct copy. (E.g. a firmware update with new settings).
Yes, that's a danger with such a solution. You can improve consistency by making each section have a different name (such as ".settings.123" or ".settings.backlight") and then using KEEP(*(SORT(.settings.*))) in your linker file. At least that way you get the same order each time. However, that won't help if one section grows and therefore changes the addresses of all the other sections.
> > Besides as I think you said usually something needs access to everything > anyway, like a UI or diagnostics module.
I am not sure if I actually /said/ that, but I did say that if your backlight module needs to preserve information, and the settings module handles this preservation, then some coupling between the two modules is unavoidable.
> >> Your code refers to >> the parameters using sensible names, rather than numbers, you don't get >> overlap or gaps (unless you want them, of course), and you can easily >> change things when you need to. And when one part of your program >> writes parameter "backgroundColour" and another part reads parameter >> "backgroundColor", you get a compile-time error rather than weird >> behaviour at run-time. >> >> But passing the data back and forth through functions like >> "update_parameter" and "get_parameter" is an alternative to accessing >> the struct directly, and can be easier to manage. It is certainly >> convenient if you want to trigger automatic saving of parameters. > > With the single struct idea I periodically run a checksum to detect a > change.
There are (as always!) many ways to handle this sort of thing - a periodic check can be a good way to do it.