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.


Log in to reply
 

Suggested Topics

16
Online

11.4k
Users

11.1k
Topics

112.7k
Posts