Non-Volatile Data Storage Help

Hello,

I am new to Particle and using the Photon module.

I am connecting several pairs of photon devices and trying to store the “paired” device ID in non-volatile memory. I’ve had success using the EEPROM functions, get() and put() to store and read a 24 char string (the size of the device IDs), but the EEPROM data is lost upon power loss or reset. When I utilize cloud function below, I am returned a “1” which tells me that the EEPROM write worked correctly. I am using Particle Dev to check the “pairedID” string through a cloud variable.

Am I doing something wrong?

My code is very simple:

//setPairedCandle() is a cloud function 
int setPairedCandle( String candleID )
{   
    String IDcheck; 
    
        EEPROM.put( 0, candleID );    //Store candleID into Flash memory
    
        EEPROM.get( 0, IDcheck );     //Read candleID from Flash memory

    if( (strcmp(candleID, IDcheck))==0 )    //If successful EEPROM write
    {
        EEPROM.get( 0, pairedID );    //Update the pairedID
          
        return 1;   
    }
    else
        return 0;   //Return 0 if unsuccessful

} 

I am not partial to using the EEPROM functions, I just need a way to permanently store the device ID of the paired candle on the photons. Any help would be much appreciated!

Thanks,
-Joshua

Shouldn’t you first EEPROM.get() the data and only EEPROM.put() when the result of get() indicates a new device?
The way I see this (since you don’t show the rest of your code) pairedID only gets populated in that function, or where and how else?
Could you show the rest of your code?

1 Like

Hello,

True, it would make sense to build a checking mechanism into this function, but I don’t see how that would solve the problem I am having.

pairedID is a global variable and is initially populated using EEPROM.get() in setup(). See below.

    //Definition under global variables:
    String myID, pairedID;  //Device IDs for this device and it's paired device
    
    void setup()  
    {
            //Irrelevant code has been removed from setup()

            EEPROM.get(0,pairedID);        //Retrieve ID of paired device from EEPROM (24byte charArray)
            Particle.function("pairedCandle", setPairedCandle);   //Cloud function used to set the ID of the paired device. (stores ID in EEPROM[0-23] ) 
            Particle.variable("pairedID", pairedID);
    }

When I flash the device, the “pairedID” variable reads blank in Particle Dev. Using the function setPairedCandle(), I manually assign the deviceID and immediately afterward I can see that the pairedID variable is now set to exactly what I input.

At this point, if I hit “reset” on the photon (or temporarily cut its power), when it comes back on, “pairedID” either reads blank again, or worse, it has a few random characters, typically including ‘�’.

Now, I tried this exact same code using just an int variable instead of string, and it worked perfectly and persisted after reboot. So perhaps I am not handling strings properly? Or maybe EEPROM.get() doesn’t properly with string types?

Another possibility is that EEPROM functions are being interrupted when handling a 24 char string. I am running four different timers that interrupt the system to run routines for sensors and communications. However, I am not “starting” these timers until the end of setup().

//Set-up timers for regular routines:
Timer LED_timer(50, update_LEDs);        //20Hz
Timer qTouch_timer(250, update_qTouch);  //4Hz
Timer IR_timer(100, update_IR);          //10Hz
Timer Cloud_timer(1000, update_Cloud);   //1Hz
 
setup()
{
  //....

  //Start timers:
    LED_timer.start();
    qTouch_timer.start();
    IR_timer.start();
    Cloud_timer.start();
}

Thanks,
-Joshua

Hi @jameson

@rickkas7 has this very nice post showing how to write many types of data into EEPROM.

2 Likes

I’d always favour C strings over String objects - there I exactly know what’s going on :wink:

The thing with objects is that they need to be serializable in order to be stored away, and I doubt this is happening with EEPROM.put() and EEPROM.get() for any object.
I’d rather think you just get the static parts of the object stored away and the dynamically allocated portion (the actual string content) gets left behind.
So when you read back the just stored away pseudo-String, you’ll still find the string in its exact same spot on the heap and you’re good, but not so after a reboot.

So either try

EEPROM.put( 0, candleID.c_str() );
// or
EEPROM.put( 0, (const char*)candleID );

Or even better stuff Strings completely and start using proper C strings :wink: that saves you issues like this - with C strings you get what you expect.

2 Likes

Yes, what ScruffR said. Saving a String object using EEPROM.put() doesn’t work as you’d think it should - it won’t save the contents of the string.

The reason is that the underlying code assumes a fixed-size primitive type (int, double, etc.) or structure. The code is:

    template <typename T> const T &put( int idx, const T &t )
    {
        HAL_EEPROM_Put(idx, &t, sizeof(T));
        return t;
    }

It’s saving the String class meta data, not the actual string, which is in an allocated pointer that the EEPROM doesn’t know anything about. The reason why it works until reset is because it’s saving the pointer value, which remains valid-ish until reset.

5 Likes

Thanks guys! Got it working.

I first tried casting the String as (const char*) in EEPROM.put() and also tried using the .c_str() function, but neither worked. (They may have been storing the first character in the String, but can’t verify this).

However, I did get it working properly by using C strings. (See below) The only thing I don’t understand is that the char arrays need to be 25 bytes to fully capture the device IDs, which seem to only be 24 chars long.

char myID[25];
char pairedID[25];
char IDcheck[25];

int setPairedCandle( String candleID )
{   
    char CID[25];
    char IDcheck[25];
      
    candleID.toCharArray(CID,25);  //Convert input String to char array
        
    if( (strcmp(CID, pairedID))==0 )    //Check to see if the candleID is new / different
        return -1;  //Indicate that this is the same ID that is already stored.
            
    //Store new candleID into Flash memory
    EEPROM.put( 0, CID );   
        
    EEPROM.get( 0, IDcheck );
  
    if( (strcmp(candleID, IDcheck))==0 )    //If successful EEPROM write
    {
        EEPROM.get( 0, pairedID );   //Update the pairedID
              
        return 1;   
    }
    else
        return 0;   //Return 0 is unsuccessful
    
}  //end of pairedCandle()

Thanks again!
-Joshua

C char arrays use a trailing zero character to tell where the end of the string is, so that is normal.

1 Like