Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: EEPROM "put"/"get" problem

  1. #1
    Member
    Join Date
    Apr 2020
    Location
    HyŤres, France
    Posts
    21

    EEPROM "put"/"get" problem

    Hi all

    Can anyone help me out with this seemingly none complicated problem.

    I've created a C# program to send serial data to a Teensy 3.2. On the Teensy there is the code below. The idea is that when the Teensy detects a string, RESI_A for example, a float number is put into the EEPROM.
    The code seems to work for any one if statement, but when I try a different if statement the data in the other addresses gets screwed up. Bizarre...

    For example when I put a float in a specific address, the data in the other addresses seems to get screwed up..

    Can anyone see my mistake?


    Code:
    #include <EEPROM.h>
    String val;
    float RESI_A = 1.0f;
    float RESI_B = 1.1f;
    float RESI_C = 1.2f;
    float RESI_D = 1.3f;
    float EEPROMA;
    float EEPROMB;
    float EEPROMC;
    float EEPROMD;
    
    void setup() {  
      Serial.begin(9600);  
      val = "NONE";  
    }
    
    void loop() {  
     
      if (Serial.available()){   
        val = Serial.readString();
         
        
       if (val == "1")
         {
          EEPROM.put(0, RESI_A);      //Write the value to the appropriate byte of the EEPROM.          
          }
          else if (val == "2")
          {
          EEPROM.put(1, RESI_B);      //Write the value to the appropriate byte of the EEPROM.                                           
           }
          else if (val == "3")
            {
              EEPROM.put(2, RESI_C);      //Write the value to the appropriate byte of the EEPROM.                                          
             }
          else if (val == "4")
            {
              EEPROM.put(3, RESI_D);      //Write the value to the appropriate byte of the EEPROM.                                          
             }
      }
             val = "NONE";
    }

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,084
    EEPROM indexes are to single BYTES - as indicated in the posted code comment :: appropriate byte of the EEPROM.

    .put() and .get() are sizeof() aware and will write the four BYTES of the float variables passed in this example.

    something like this (assuming all are FLOAT) needs to be done for proper indexing and not have the data BYTES overwrite one another:
    Code:
          EEPROM.put(0 * sizeof(float), RESI_A);      //Write the value to the appropriate byte of the EEPROM.          
          }
          else if (val == "2")
          {
          EEPROM.put(1 * sizeof(float), RESI_B);      //Write the value to the appropriate byte of the EEPROM. 
    
    // ...

  3. #3
    Member
    Join Date
    Apr 2020
    Location
    HyŤres, France
    Posts
    21
    Thanks Defragster

    That did the trick, but I had to apply the same for the "get" command to receive the correct values from the EEPROM otherwise I got rubbish.

    Code:
      EEPROMA = EEPROM.get(0 * sizeof(RESI_A), RESI_A); 
      EEPROMB = EEPROM.get(1 * sizeof(RESI_B), RESI_B); 
      EEPROMC = EEPROM.get(2 * sizeof(RESI_C), RESI_C); 
      EEPROMD = EEPROM.get(3 * sizeof(RESI_D), RESI_D);

  4. #4
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,084
    Cool - glad issue popped out when I looked. That was just a HACK Test ...

    Indeed as noted GET and PUT index and work the same - but the code only showed .put()'s.

    Note:: that 'solution' only works when ALL items are the same size.

    In reality the start offset of any given 'variable' is based on the the sum of the bytes used before it.

    For example if the items stored with that logic were in order :: [0] : 32 bit int, [1] : 16 bit int, [2] : 8 bit char
    >> Those would still collide using byte offsets : 0, 2, 2

    So if mixed data sizes are ever used the problem will likely return (or bytes could be skipped unused) without attention to that issue
    >> The offsets should come out to : 0, 4, 6

    That would require deriving a usable offset list for reference.

  5. #5
    Member
    Join Date
    Apr 2020
    Location
    HyŤres, France
    Posts
    21
    Hi defragster

    Yes, i think I have hit the problem you described above. At address 0, i write a float (for example 1.1), but at address 4 I want to write int (200 for example), but it doesnt seem to like that....So how do I count the space used so i dont have a problem?

  6. #6
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,084
    Like float, an 'int' is 32 bit? To be sure user int32_t. If everything is 4 bytes it will stack okay.

    Offhand ... without seeing the whole of the usage needs ... not sure of a neat way that doesn't take overhead, manipulation and calculation to account for each item before this item to get an offset.

    Making a struct would be clean except for writing more than desired.

    If alternate 'byte sizeof(vars)' are needed then perhaps segment them into groups with a fixed offset between them to avoid over writing.

  7. #7
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    122
    Here's a simple demo of how I might do it. Note you can get into trouble if you change the struct definition, as all the structure members are likely to move, but it makes life pretty simple and you don't have to spend time counting bytes:
    Code:
    /*
     * Create a struct to store stuff we want to 
     * store in and get from EEPROM
     */
    #include <EEPROM.h>
    
    #define EEPROM_BASE 11 // be weird - make it odd to prove it works
    struct saveStruct {
      float flt;
      char ch1,ch2,ch3;
      short shrt;
    } saved;
    
    void setup() {
      Serial.begin(115200);
      EEPROM.get(EEPROM_BASE,saved); // restore from EEPROM
      Serial.println(sizeof saved);  // 12 bytes due to padding to 32-bit boundaries
      Serial.println();
      Serial.printf("%.6e\n",saved.flt);
      Serial.println(saved.ch1);
      Serial.println(saved.ch2);
      Serial.println(saved.ch3);
      Serial.println(saved.shrt);
    
      saved.ch2='2';
      EEPROM.put(EEPROM_BASE+offsetof(saveStruct,ch2),saved.ch2);
      saved.flt=9.876543e10;
      EEPROM.put(EEPROM_BASE+offsetof(saveStruct,flt),saved.flt);
      saved.shrt=12345;
      EEPROM.put(EEPROM_BASE+offsetof(saveStruct,shrt),saved.shrt);
    }
    
    void loop() {
    
    }
    Note the first time you run this you'll get junk. The second time you run it, flt, ch2 and shrt will have the saved values, but because we never set ch1 and ch3 they're still junk.

    Cheers

    Jonathan

  8. #8
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,084
    Quote Originally Posted by h4yn0nnym0u5e View Post
    Here's a simple demo of how I might do it. Note you can get into trouble if you change the struct definition, as all the structure members are likely to move, but it makes life pretty simple and you don't have to spend time counting bytes:
    ...
    Note the first time you run this you'll get junk. The second time you run it, flt, ch2 and shrt will have the saved values, but because we never set ch1 and ch3 they're still junk.

    Cheers

    Jonathan
    Nice work showing usage of : cppreference.com/w/cpp/types/offsetof

    Not used that before - but seemed ordering in a struct could lead to ability of the compiler to resolve offsets without 'messy manual' accounting.

    Indeed on 'first use' - or with any change to the 'struct' - the contents will be garbage, so checking for a Version stamp element on startup to init would be called for.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •