Best way to store large data in eeprom
-
Hi,
In my node (ATMega328p) I want to store a duration in seconde in Eeprom....
This duration can range from 0 to 86400 (1day :))
I think use the method :
void saveState(uint8_t pos, uint8_t value);
but uint8_t can only store value range from 0 to 255So, I found 2 solutions :
- Cut the duration in 2 variables : 1 for minutes, 1 for seconds, and store them at 2 differents positions.
- Store in a uint32_t type and not use saveState method but use mySensor internal method : hwWriteConfigBlock(__buf, __pos, __length) with the correct param.
In your opinion, what is the best choice ? or perhaps an other solution ?
Thanks in advance
-
Third option:
int duration = 4000; saveState(0, (duration >> 8) & 0xff); saveState(1, duration & 0xff); // And loading duration = loadState(0) << 8 + loadState(1);
-
@Tetnobic the first solution won't work. There are 1440 minutes in a day
I use the method suggested by hek when storing the highscore for my MySesnors-powered Tetris game (soon to be published), except that I use an unsigned int.
Using highByte(), lowByte() and word() might be more readable than the bit shifting though. Like this:
unsigned int duration = 4000; saveState(0, highByte(duration)); saveState(1, lowByte(duration)); // And loading duration = word(loadState(0), loadState(1));
-
@hek thanks for your Nice 3d solution,
I do not usually use the bit shifting technique, I guess the max value is 8 * 2 bits : 65 535 ?@mfalkvidd right 1440 minutes in a day... I am a goat... Thanks for the methods, I think I will use this...
-
@Tetnobic correct, the max value for a 16-bit unsigned integer is 2^16-1 which is 65535. See https://www.arduino.cc/en/Reference/UnsignedInt for details.
-
@mfalkvidd so not enough to store 1 day (86400s) , can I do same things with int32 ?
-
@Tetnobic true, nice catch
32 bits (unsigned long) would work. You'd have to use bit shift though, I don't think there are equivalents for high/lowByte and word.
unsigned long duration = 4000; saveState(0, (duration >> 24) & 0xff); saveState(1, (duration >> 16) & 0xff); saveState(2, (duration >> 8) & 0xff); saveState(3, duration & 0xff); duration = loadState(0) << 24 + loadState(1) << 16 + loadState(2) << 8 + loadState(3);
But your original idea with hwWriteConfigBlock would be easier to read I think.
-
@mfalkvidd yes for this solution, I guess that hwWriteConfigBlock method access to the eeprom in one time, contrary to bit shifting technique that need 4 saveState so 4 access to the eeprom ?
-
I try this :
#define EEPROM_SLEEP_DURATION_ADDRESS 0 uint32_t sleepDurationInS = 86399; hwWriteConfigBlock((void*)sleepDurationInS, (void*)(EEPROM_LOCAL_CONFIG_ADDRESS+EEPROM_SLEEP_DURATION_ADDRESS), 32); hwReadConfigBlock((void*)&sleepDurationInS, (void*)(EEPROM_LOCAL_CONFIG_ADDRESS+EEPROM_SLEEP_DURATION_ADDRESS), 32);
but seems no work my node freeze at this method
-
@Tetnobic that looks correct to me, but I am no c/c++ expert so pointers and casting is scary for me Hopefully someone with better skills can give some clarity.
The code in the security personalizer seems to use the same syntax.
-
Length should be 4 not 32.
-
@hek right sizeof uint32_t : 4
it works with :
#define EEPROM_SLEEP_DURATION_ADDRESS 0 uint32_t sleepDurationInS = 86399; hwWriteConfigBlock((void*)&sleepDurationInS, (void*)(EEPROM_LOCAL_CONFIG_ADDRESS+EEPROM_SLEEP_DURATION_ADDRESS), 4); hwReadConfigBlock((void*)&sleepDurationInS, (void*)(EEPROM_LOCAL_CONFIG_ADDRESS+EEPROM_SLEEP_DURATION_ADDRESS), 4);
-
Just for info, I found others methods to save data in eeprom :
in <avr/eeprom.h> there is :uint8_t eeprom_read_byte (const uint8_t *__p) uint16_t eeprom_read_word (const uint16_t *__p) uint32_t eeprom_read_dword (const uint32_t *__p) float eeprom_read_float (const float *__p) void eeprom_read_block (void *__dst, const void *__src, size_t __n) void eeprom_write_byte (uint8_t *__p, uint8_t __value) void eeprom_write_word (uint16_t *__p, uint16_t __value) void eeprom_write_dword (uint32_t *__p, uint32_t __value) void eeprom_write_float (float *__p, float __value) void eeprom_write_block (const void *__src, void *__dst, size_t __n) void eeprom_update_byte (uint8_t *__p, uint8_t __value) void eeprom_update_word (uint16_t *__p, uint16_t __value) void eeprom_update_dword (uint32_t *__p, uint32_t __value) void eeprom_update_float (float *__p, float __value) void eeprom_update_block (const void *__src, void *__dst, size_t __n)
It is to these methods that the aliases are made in the file MyHwATMega328.h
#define hwReadConfig(__pos) eeprom_read_byte((uint8_t*)(__pos)) #define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t*)(__pos), (__val)) #define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length)) #define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((void*)(__buf), (void*)(__pos), (__length))
-
@Tetnobic the hw* functions is a way to abstract the underlying hardware. Many MySensors fans use non-avr hardware, for example ESP8266.
You can of course choose to optimize for a single platform in your own sketches, but we strive to make the MySensors example sketches available for as many platforms as possible.