Backup RAM not working [SOLVED]

Im trying to work out the retained RAM working on the photon…

here is a simple demo app to show the issue… reading the value straight away is ok, but then it just goes back to 0

retained int saveValue = 10;

void setup() {
    Serial.begin(9600);
}

void loop() {
        Serial.println(saveValue);
        saveValue = 15;
        Serial.println(saveValue);
        delay(2000);
}

Yes very strange and not what we’d expect. In my example we’d expect 10, 15, 15, repeating… if you press reset during my 5 second delay it should come up and print 15, 15, 15. But instead here’s the code and output:

retained int saveValue = 10;

void setup() {
    Serial.begin(9600);
}

void loop() {
        Serial.println(saveValue);
        saveValue = 15;
        Serial.println(saveValue);
        Serial.println(saveValue);
        delay(5000);
}

/* OUTPUT

0
15
0

0
15
0

0
15
0

*/

yeah… something a miss there… ive tried so many things to make it work now. took me so long to work out what was causing the number to always be zero… i thought it was the way i was publishing the data and had to strip it back to nothing to find it.

each time loop() returns, you lose control to whatever called loop.
In Arduinos, that is a do-nothing infinite loop. But that’s not assured.

Initialized static variables in C are initialized once prior to main() being called. So you are at the mercy of whatever main() is doing, and that may differ from one operating environment to another. The “loop()” concept was find for a trivial 8 bit microprocessor with no background processing (such as a network stack to manage).
Perhaps if you code loop() to have a while(1) loop, you won’t lose control.

The docs are missing one key detail:

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

Add this to the top of the sketch to enable the backup ram.

EDIT: docs updated

3 Likes

Thanks @mdma that worked a treat!

1 Like

Is it working through a reset for you @Hootie81? It’s not for me, saveValue comes up as 10 for me or if not initialized in the program it will be 0 after reset.

Ok figured this out… thought it was ok to hard reset it (pushing the reset button) but it only retains memory with a soft reset, E.g., System.reset();

I’ll update the docs with that clarification :wink:

Edit: docs updated: http://localhost:8080/reference/firmware/photon/#backup-ram

1 Like

@BDub, will it retain memory through a hard reset if Vbat is present?

I think it held the value when i pushed the reset button while on the battery shield, it had a weird number of -54522 in it when i got it working. I had to remove the Photon from the shield to get the number back to Zero.

I’ll test it again soon, for some reason the project stopped pinging at 8pm yesterday

Tried it with VBAT jumpered to 3V3 and the retained variable was reinitialized, so I’m pretty sure the answer is no… but it was a 60 second test.

@BDub, I just tested it too, on the sparkfun battery shield, pushing the reset button keeps the retained value. code im using is on the water usage monitor thread i posted last night.

Hmm, nothing I’m doing seems to retain the value with a hard reset. I’m powering VBAT with +3.3V from a second source now. Also just powering off the retained variable photon while VBAT power is maintained doesn’t seem to work currently for me. Can you verify with the example app in the docs @Hootie81 that you definitely see values retained through a hard reset when powered with the battery shield?

@BDub oooh this is interesting… it works sometimes (and i know the secret)… both with and without the battery shield and with and without vbat being powered.

code as per the docs is working as expected, first run after power-up is 10 and 20, after it restarts (after the sleep) its 20 and 20. pressing the reset button it still is 20 and 20

then flashing this code

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

retained int saveValue = 10;

void setup() {
    Serial.begin(9600);
}

void loop() {
        Serial.println(saveValue);
        saveValue = 15;
        Serial.println(saveValue);
        Serial.println(saveValue);
        delay(5000);
}

it shows
20
15
15
so it even retains when flashing new firmware.

but then i also had a point where it stopped working and went
10
15
15
after every press of the reset button…

So lots of playing around and i found if the device is unplugged, then plug it in and run the code once to set the retained value, and then reset it stops working and will continue to not work.
The key is sleep… put the device to deep sleep using the code exactly as per the docs… and it starts working again tested this a couple of dozen times now and its consistent.
so as long as you put the device to sleep at least once after the power is applied it works every time. flashing new code without removing power is OK too.

2 Likes

Great detective work @Hootie81! Confirmed your findings that deep sleep must be called once which will allow hard resets (and actually soft resets as well). I think what this means is whatever deep sleep is doing, is also something that needs to be enabled with:

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

The one thing I’m still not getting to work though is even after I put the photon to deep sleep, if I turn it’s USB power off while VBAT is still powered from a second Photon’s 3V3 and GND, the first photon will reinitialize it’s retained variables when I power it back up. It should also work if I don’t call deep sleep and doesn’t, but we found there is some extra initialization to backup ram with deep sleep code.

Deep sleep also seems to make the software reset function properly as well. If I don’t deep sleep once while VIN is powered, it doesn’t seem to retain variables after I OTA code that starts System.reset()'ing instead of deep sleeping.

I’ll dig into what exactly deep sleep is doing that’s so magical.

EDIT: It appears to work when not using the RTC as well, i.e., System.sleep(SLEEP_MODE_DEEP); so HAL_Core_Enter_Standby_Mode(); is the next thing to dig into.

2 Likes

So the code currently (v0.4.6) attempts to initialize SRAM if it’s not waking up from Standby mode, but should instead be initializing based on if it powered up when the Backup RAM is enabled. Since it’s a bit tricky to store a system variable in SRAM for this purpose, checking the Backup Regulator Ready status bit will do nicely; which is a hardware controlled bit that won’t be cleared if we are waking up from Standby, software or hardware reset. This backup regulator is only enabled if we are enable Backup RAM, so this is perfect.

I’ve been testing this and it’s rock solid now. I’ll push this as a branch fix/PR to be included in v0.4.7 and update the docs (possibly as PR). Docs really need a matrix table to show all of the different states for SRAM. I think that would make it super clear when SRAM is initialized and when it’s retained (at least that’s the hope).

Was chasing my tail a bit initially trying to debug this because Backup SRAM will not currently work when compiling as monolithic. And monolithic compiles about twice as fast as modular when iterating locally. I’ll submit this as a separate issue.

4 Likes

@BDub I was trying to store the result of putting the battery gauge to sleep on the battery shield, and publish it next time the photon comes on, due to the publish requiring a string i thought i would try having a retained string, it compiles OK and flashes but it doesn’t work… i guess because string is a class… does this sound right?

there are plenty of other ways i can do this… it was just something i noted

I bet it’s working with Strings, but they don’t appear to work because they have an underlying memory management system that moves data around in memory. If you saved the result of your String to a retained char myChar[64]; before you programmatically power down, and then restore it on boot, that would work. It would obviously not work for asynchronous power outages or resets… but it still might work most of the time if you immediately saved your String to a char array directly after manipulation. Also whatever Mat has planned to cook this up might make Strings work with retained memory as well.

1 Like

One thing I noticed with a test program is that unplugging the Photon for less than about 10 seconds and plugging it back in, retains the SRAM state. It seems like it needs to burn through residual power before it goes blank. Also, I had a small capacitor that could have been having this effect as it drained so keep in mind other components you have attached. That might help some people.