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 255 😞

    So, 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


  • Admin

    Third option:

    int duration = 4000;
    
    saveState(0, (duration >> 8) & 0xff);
    saveState(1, duration & 0xff);
    
    // And loading 
    
    duration = loadState(0) << 8 + loadState(1);
    
    

  • Mod

    @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...


  • Mod

    @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 ?


  • Mod

    @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


  • Mod

    @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.


  • Admin

    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))
    

  • Mod

    @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.


 

296
Online

7.8k
Users

8.7k
Topics

93.0k
Posts