1

Problem: I need to retry at least 3 times (before giving up) to reconnect my NodeMCU if it doesn't get connected to Wifi, through deep sleep cycles in order to save batteries. I thought to use RTC memory to save a counter, but it doesn't work because content of RTC RAM is unpredicatble at first power up.

Following is a NOT WORKING code, but it gives the idea of what I need to achieve. The problem is: the kounter variable is persistent through cycles, but its very first value is unpredicatble.

#define DONEPIN 5
uint32_t kounter;

void setup() {
    digitalWrite(DONEPIN, HIGH);
    //WiFi setup functions...
    // .....
    if (WiFi.status() != WL_CONNECTED) {
        ESP.rtcUserMemoryRead(0, &kounter, sizeof(kounter));
        kounter++
        if (kounter > 3) {
            digitalWrite(DONEPIN, LOW);
        }
        ESP.rtcUserMemoryWrite(0, &kounter, sizeof(kounter));
        ESP.deepSleep(60e6); 
    }
}
3
  • @Majenko interesting! Didn’t know that. I removed my comment.
    – Gerben
    Jul 29 '18 at 20:15
  • @Gerben So did I :P
    – Majenko
    Jul 29 '18 at 20:16
  • 1
    You can differentiate between first powerup and resets (after deep sleeps) by using rtc_get_reset_reason(0). If I’m not mistaken this should return a 1 on powerup. So when this returns 1 overwrite the RTC memory with zero. Otherwise read the memory.
    – Gerben
    Jul 29 '18 at 20:34
2

The simplest trick is to use more than one memory location. Have one, as you have now, as a counter, and then have one or more as a "This has been configured" flag.

Ideally you want the flag to have a very low probability of occurring randomly, so using a combination of a number of memory locations would improve that.

For instance, if you read memory locations 1-4 and look for four specific bytes, that gives you about a 1 in 4 billion possibility of it happening randomly.

If you don't see those four bytes, you set the counter byte to 0 (or whatever you want your initial value to be) and set the other 4 memory locations to contain your 4 flag bytes.

Using 8 bytes for your flag would give you in the order of 1 in 1.8x1019 chance of it occuring randomly.

These "flag byte combination" are often called "magic numbers" and are used all over the place to identify either what something is, or if something is valid.

2
  • So, can I use a struct { byte counter; byte validation[7]} ? Jul 29 '18 at 19:05
  • 1
    Sure, you could do. I don't know what the functions allow you to easily pass though, so it may be simpler to just directly access the memory's bytes.
    – Majenko
    Jul 29 '18 at 20:09
2

I realize this is really old, but it is still the top of the list when you search for RTCmem read/write. While it isn't maybe as "by the book" as the 'correct' answer above, there is a really simple way to deal with the "the rtcmem value is something ridiculous on first read" issue. When you first power on the esp8266 or after a button-based reset, the rtcmem value WILL be something insane. You can account for it in the code by ignoring anything that is outside the count you want. Since my application "sleeps" for 4 hours, which in esp8266 means 4, 1 hour loops, I simply say if the rtcMem value is outside that range, it is obviously bogus, set it to what I want, and go about your business:

void writeToRTCMemory() {
  if (rtcMem.count == MAXHOUR) {
    rtcMem.count = 1;
  } else {
    if (rtcMem.count < 1) {
      rtcMem.count = 1;
    }
    if (rtcMem.count > 4) {
      rtcMem.count = 1;
    }
    rtcMem.count++;
  }

As long as your device has not lost power, or you have not pushed the reset button, this will keep it looping the way you want for as long as it has enough juice to deep sleep. (My solar powered sensors with this loop last around 2/2.5 weeks in the mid winter and much longer in summer)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.