Register / Login  |  Desktop view  |  Jump to bottom of page

tcMenu Arduinio library » Auto-Save Values on Callback

Author: jonboy545
30/03/2020 03:34:08
Instead of having a separate menu item that's calback contains menuMgr.save(eeprom); , i thought I could just add menuMgr.save(eeprom); to the end of each menu item's callback so after setting the value it "auto saves".

However, 2 things happen. One, the value isn't written to EEPROM, and two some values fail to load on the next boot cycle.

Example:

Two basic callbacks updating an integer.

void CALLBACK_FUNCTION setBoilerTemp(int id) {
    serviceBoilerSetTemp = menuConfigurationMachineSettingsServiceBoiler.getCurrentValue();
    //menuMgr.save(eeprom);
}

void CALLBACK_FUNCTION setCoffeeBoilerTemp(int id) {
    coffeeBoilerSetTemp = menuConfigurationMachineSettingsCoffeeBoiler.getCurrentValue();
    //menuMgr.save(eeprom);
}


I have a seperate callback for "Save Settings" action item built into the menu. It works fine.

void CALLBACK_FUNCTION saveSettings(int id) {
  menuMgr.save(eeprom);
}



Again, with the menuMg.save(eeprom); commented out, the EEPROM values are saved correctly, when the menu option "Save Settings" is selected. The values are read correctly on start up.
With them un-commented some values are loaded with a 0 value, and when adjusting the value they do not save as expected.


What am I doing wrong?

Thanks!
Jon

Author: davetcc
30/03/2020 10:29:43
There may be a bug in the EEPROM storage, I'd need to take a look. However, I certainly wouldn't save to EEPROM like that. EEPROM storage is very, very slow, and has a limited number of writes. When you write to EEPROM, there are significant delays while it actually modifies each bit of the storage. Hooking that to a callback is dangerous.

The usual way to handle this situation when using regular EEPROM storage is to use a power loss detection circuit and when the power loss is detected, write the values out immediately (maybe using an IoAbstraction marshaled interrupt) when the power loss condition occurs: https://www.thecoderscorner.com/electronics/microcontrollers/psu-control/detecting-power-loss-in-powersupply/

In commercial circuits there are two commonly used methods, one the way I describe above, the second is to use battery-backed non-volatile memory for the storage. If you use the later, you could provide your own EEPROM implementation for it as it would probably be quite custom hardware.

Author: jonboy545
30/03/2020 13:41:36
Thank you for the fast reply Dave.

I will refrain from writing to eeprom on each change.

Is it safe to still have a "master save" callback. Where the only menu function is to save to eeprom, and it wouldn't be done often.

How much time are we talking about to write to eeprom? My menu isn't utilizing much now, and I expect by the time I'm done the number of spaces will be roughly doubled. I'm guessing it's 2 bytes per field? So I'm at 46 bytes now (up to space 23).
More than one second? I have not been taking a wait time into account. Thinking I need to add a delay with a "confirmation" to the save settings callback, to make sure nothing else happens while writing to eeprom.

EDIT: Should clarify this is an Arduino Mega 2560, using builtin Avreeprom.

image

Author: davetcc
30/03/2020 17:25:04
That's a fairly substantial menu from the image there!

EEPROM's are very slow, think milliseconds per write. They are usually good for least 100,000 writes, but if you had something wired to a rotary encoder, you could exceed that in a couple of weeks easily.

It is completely safe to have a save menu option as per the examples I've written. When you don't have power-down detection, this is the second-best option.

By the way, I don't think any special handling should be needed during the save, each write is fairly atomic.

As an aside, if you look at the ESP WiFi example the save function presents a dialog to indicate it's committed to flash, you could do the same if you wanted extra confirmation.

Thanks
Dave.

Author: davetcc
30/03/2020 17:33:06
In terms of sizes:

Analog and enum items: 2 bytes
Boolean items: 1 byte
Large numbers: 8 bytes
IpAddress: 4 bytes
Time items: 4 bytes
Text items: Length of the text item

case AnalogMenuItem _: return 2;
case BooleanMenuItem _: return 1;
case EnumMenuItem _: return 2;
case LargeNumberMenuItem _: return 8;
case EditableTextMenuItem txt:
  if (txt.EditType == EditItemType.IP_ADDRESS) return 4;
  else if (txt.EditType == EditItemType.PLAIN_TEXT) return txt.TextLength;
  else return 4; // time always 4
default: return 0;

Author: jonboy545
30/03/2020 21:21:54
Awesome, thank you for the info Dave.

The menu is quickly growing out of control haha. However the code happily puts along! A true testament to the foundation you have built.

I am designing an "universal" espresso machine control board. I restore old Italian semi-automatic espresso machines in my spare time and the control boards are getting harder and harder to find, and repairing them I feel takes more time than me coming up with an alternative. So I'm designing a "universal" board, that will have a much higher amount of customization including variable pressure profiles, support for dual boilers, etc etc. (not sure if you're in the espresso world at all, if not I'm sure that all sounds like garbldy goop.

Having a very nice menu, with LCD, has been a feature I'd love to add to my own (and other) espresso machines, so with the large number of GPIO pins on the mega, and your wonderful menu the dream is slowly becoming a reality.

For now, this is for my own personal machine, and a few for friends/family however in the future I'd like to make a product available to people I can sell.

When you get time, can you send me any info on commercial licensing for the menu? I see on your site where you offer commercial support/customization. I'm going to take it DIY as far as I can, but want to make sure if I do (big IF) make this a commercially viable product I do it on the straight'n arrow.

Cheers,
Jonathan

Author: jonboy545
30/03/2020 21:23:54
Here's where she stands so far...
image




Register / Login  |  Desktop view  |  Jump to top of page