EEPROM "put"/"get" problem

Status
Not open for further replies.

GiGiUK

Active member
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";
}
 
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. 

// ...
 
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);
 
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.
 
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?
 
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.
 
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
 
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.
 
Status
Not open for further replies.
Back
Top