ESP8266 inherit from EEPROM not working

Hi everyone,

I'm moving a project of mine from an Arduino nano to an ESP8266.
As expected some of the code needs to be changed, including the way I use EEPROM.
I looked up as much as I could find online, and at first it didn't seam to hard, the ESP EEPROM simulation is nearly identical as the real EEPROM on Arduino.

However I'm getting some strange behavior and I can't figure out what I'm doing wrong. Here's my code:

#include <EEPROM.h>

// Set timeout
void set_Connection_Timeout(byte val) {
  EEPROM.write(1, val);
  EEPROM.commit();
}
// Get Timeout
byte get_Connection_Timeout() {
  return EEPROM.read(1);
}

unsigned long connectionTimeout = get_Connection_Timeout();
unsigned long connectionTimeoutDelay = connectionTimeout * 1000UL;


void setup() {

  EEPROM.begin(512);
  Serial.begin(9600);

  set_Connection_Timeout(5);

  Serial.println();

  Serial.print("get_Connection_Timeout():");
  Serial.println(get_Connection_Timeout());

  Serial.print("connectionTimeout:");
  Serial.println(connectionTimeout);

  Serial.print("connectionTimeoutDelay:");
  Serial.println(connectionTimeoutDelay);
}

void loop() {
}

Now this will print the following from my Wemos D1 Mini clone into the Serial console:
16:46:39.298 -> ⸮HpY⸮CGH,l`:I⸮⸮
16:46:39.437 -> get_Connection_Timeout():5
16:46:39.437 -> connectionTimeout:0
16:46:39.437 -> connectionTimeoutDelay:0

Aside from the strange characters printed at boot???...
Why are connectionTimeout and connectionTimeoutDelay both 0? They should be 5 and 5000 respectively, right?

I really hope someone can explain, I've been searching for an answer all afternoon.
Am I going nuts? :sweat_smile:

EDIT:
To clarify, I realize this won't output the correct numbers until after a reboot/power cycle, as the vars are set before a number has been written to EEPROM.

Any help appreciated!
Luck7

Aaaand I just figured out that this does work:

#include <EEPROM.h>


// Set Timeout
void set_Connection_Timeout(byte val) {
  EEPROM.write(1, val);
  EEPROM.commit();
}
// Get Timeout
byte get_Connection_Timeout() {
  return EEPROM.read(1);
}

unsigned long connectionTimeout;
unsigned long connectionTimeoutDelay;

void setup() {

  EEPROM.begin(512);
  Serial.begin(9600);

  set_Connection_Timeout(5);

  connectionTimeout = get_Connection_Timeout();
  connectionTimeoutDelay = connectionTimeout * 1000UL;

  Serial.println();

  Serial.print("get_Connection_Timeout():");
  Serial.println(get_Connection_Timeout());

  Serial.print("connectionTimeout:");
  Serial.println(connectionTimeout);

  Serial.print("connectionTimeoutDelay:");
  Serial.println(connectionTimeoutDelay);
}

void loop() {
}

Output:
16:56:55.333 -> ⸮Hp⸮<>$(⸮lb8⸮
16:56:55.472 -> get_Connection_Timeout():5
16:56:55.472 -> connectionTimeout:5
16:56:55.472 -> connectionTimeoutDelay:5000

What I don't understand is why the fist code I posted worked fine on my Arduino nano, but not on my Wemos D1.
Can anyone explain?

You have changed WHEN the lines get executed, and they depend somewhat on what is already present in the EEPROM.

If you are going to do a commit, they should not be executed until after the commit.

It would have been nice if you had explained WHAT EEPROM library you used (there are more than one) or at least provided a link.

I'm not entirely sure what library I used. I just included the <EEPROM.h>
And yes, makes sense that it works now, but in the full code I'm using (this was just an example illustrating the problem) the EEPROM will be read at a later time, probably after at least one reboot/power cycle.

So even the first code I posted should have worked after a reboot, or am I wrong?

Or doesn't it work because the variables are defined before EEPROM.begin(512); is called in the setup()?
Which isn't required on an Arduino nano, which would explain why it works on a Nano but not in the ESP8266.

I am still trying to figure that out but without knowing what library I cannot see what EEPROM.begin(512) does and I don't think that I want to dig that deep anyway. Sorry!

vaj4088:
I am still trying to figure that out but without knowing what library I cannot see what EEPROM.begin(512) does and I don't think that I want to dig that deep anyway. Sorry!

This one: http://www.esp8266learning.com/read-and-write-to-the-eeprom-on-the-esp8266.php
Seems like my only issue is that I'd want the EEPROM library (simulator) to 'start' right away. Instead of having to do so by doing EEPROM.begin(512); in the setup.

The 512 refers to the amount of bytes that need to be available.

LuckHermsen:
I'm not entirely sure what library I used. I just included the <EEPROM.h>

The EEPROM library comes bundled with the installation of the ESP8266 boards platform. @vaj4088, you can see the documentation here:
https://arduino-esp8266.readthedocs.io/en/latest/libraries.html#eeprom
and the source code here:

LuckHermsen:
Or doesn't it work because the variables are defined before EEPROM.begin(512); is called in the setup()?
Which isn't required on an Arduino nano, which would explain why it works on a Nano but not in the ESP8266.

You got it!

pert:
The EEPROM library comes bundled with the installation of the ESP8266 boards platform. @vaj4088, you can see the documentation here:
Libraries — ESP8266 Arduino Core 3.1.2-21-ga348833 documentation
and the source code here:
Arduino/libraries/EEPROM at master · esp8266/Arduino · GitHub
You got it!

Alright, thanks for the help.
Would it be possible to work around the EEPROM.begin(x) command. Maybe change the library so it will work immediately? I have never edited libraries before.

Ok, so what was being used with the Arduino nano?

LuckHermsen:
Seems like my only issue is that I'd want the EEPROM library (simulator) to 'start' right away. Instead of having to do so by doing EEPROM.begin(512); in the setup.

Why? setup() is called when the program starts, so with that code in setup(), it does essentially start right away.

vaj4088:
Ok, so what was being used with the Arduino nano?

The Arduino AVR Boards platform of the Arduino Nano also has a bundled EEPROM library. You can see the documentation for it here:

and the source code here:

I may be wrong but I don't think that this is the correct library. The OP did

EEPROM.commit();

and there is no commit() method documented for this library.

From Libraries — ESP8266 Arduino Core 3.1.2-21-ga348833 documentation

EEPROM.write does not write to flash immediately, instead you must call EEPROM.commit() whenever you wish to save changes to flash.

Why? setup() is called when the program starts, so with that code in setup(), it does essentially start right away.

Yes but when there are variables that are initialized, it seems to me that .read() is called before begin()

and there is no commit() method documented for this library.

You are obviously not looking in the right spot. The EEPROM library for the ESP has the .commit(); and the one for AVR doesn't. Both are built in with their respective core.

Would it be possible to work around the EEPROM.begin(x) command. Maybe change the library so it will work immediately? I have never edited libraries before.

I suppose it is worth a go: from EEPROM.cpp

void EEPROMClass::begin(size_t size) {
  if (size <= 0) {
    DEBUGV("EEPROMClass::begin error, size == 0\n");
    return;
  }
  if (size > SPI_FLASH_SEC_SIZE) {
    DEBUGV("EEPROMClass::begin error, %d > %d\n", size, SPI_FLASH_SEC_SIZE);
    size = SPI_FLASH_SEC_SIZE;
  }

  size = (size + 3) & (~3);

  //In case begin() is called a 2nd+ time, don't reallocate if size is the same
  if(_data && size != _size) {
    delete[] _data;
    _data = new uint8_t[size];
  } else if(!_data) {
    _data = new uint8_t[size];
  }

  _size = size;

  if (!ESP.flashRead(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size)) {
    DEBUGV("EEPROMClass::begin flash read failed\n");
  }

  _dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time
}

i Suppose you could change the return type to 'bool', change the return in case of size <= 0 to return false; and add a return true; (of course also change the prototype return typ in EEPROM.h) and then call EEPROM.begin(512); by assigning a variable in declaration.

bool ep = EEPROM.begin(512);

it might work that way, no guarantee though, i personally would just assign the values inside of setup();

@Deva_Rishi Thanks for your suggestion.
I copied the EEPROM library to the local program folder and edited the files accordingly.

The code works and I can successfully read/write from/to EEPROM without having to call EEPROM.begin(512); in the setup().

However, I then tried to implement the same code into my existing project, but I got some weird values when reading the EEPROM. I had been looking for the issue for hours and simply couldn't find anything. I then started to doubt if maybe other functions were messing with the memory, so I started to comment functions one by one, which was quite a lot of work. Eventually I commented EVERYTING except the exact same lines as in the (still) working example I made. Still it would return 64 instead of the expected number.
I then even removed all te commented code, removed the files that weren't being used and compared the 3 remaining files 1:1. They are an exact match. Still the example code works and the stripped down version of my original project code returns the value 64 instead of the expected value.

I double checked the Flash settings, and everything is identical.

So, here is a zip with all 3 versions.
EEPROM_test > Example per your suggestion. Working
Basic_Ibus_test > Original project with implemented EEPROM. Not working.

Basic_Ibus_test_STRIPPED > Original project, fully stripped back to EEPROM_test. Text compare says identical. Not working.

For easy reference, here's the working example.
EEPROM_test.ino (main)

#include "EEPROMnew.h"
bool ep = EEPROM.begin(512);

byte get_eeprom(); // Proto
unsigned long eepromDefined = get_eeprom();
unsigned long eepromUndefined;


// Set Timeout
void set_eeprom(byte val) {
  EEPROM.write(3, val);
  EEPROM.commit();
}
// Get Timeout
byte get_eeprom() {
  return EEPROM.read(3);
}


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

  //set_eeprom(55);

  eepromUndefined = get_eeprom();

  Serial.println("");
  Serial.print("eepromDefined:");
  Serial.println(eepromDefined);

  Serial.print("get_eeprom():");
  Serial.println(get_eeprom());

  Serial.print("eepromUndefined:");
  Serial.println(eepromUndefined);
  Serial.println("");
}

void loop() {
}

EEPROMnew.h: Removed because of post limit
EEPROMnew.cpp: Removed because of post limit

To test this use the EEPROM_test example. Just uncomment "//set_eeprom(55);" in setup(), flash and run. The value will be stored in EEPROM.
Then comment the line again, flash again and run. It will still load the previously stored value.


While writing this post I tested one last thing. The only difference between the 3 versions is that the 2 non-working pieces of code have a main called main.ino. The working example is called EEPROM_test.ino
To be absolutely 100% sure, I renamed te working version to main.ino and moved it into a folder with the same name (as required per Arduino IDE for some reason) and guess what, same problem. It started returning 64 as well.

I'm really really curious what causes this. Can someone replicate the problem?
I have tried this on 2 different PC's with the same results.

Sorry for the long post, but I thought this required as much details as possible.

EDIT: So far I've tried a bunch of names for the main .ino file. For now, EEPROM_test.ino, EEPROM.ino and EEPR.ino worked.
asdfEEPROMasdf.ino, TEST.ino and MAIN.ino didn't work.

EDIT: So far I've tried a bunch of names for the main .ino file. For now, EEPROM_test.ino, EEPROM.ino and EEPR.ino worked.
asdfEEPROMasdf.ino, TEST.ino and MAIN.ino didn't work.

Well that is the first time i've heard of the names of an .ino being relevant. The only thing that occurred to me while writing the first post is that variable 'ep' is never used throughout the code, and you run the risk of the optimizer optimizing the whole thing out. For the rest it's a mystery to me. Sure the compiler does re-arrange things for us, and in particular with the assignment of values to variables. First the variable space is reserved (for all global variables) only thereafter all all assignments executed. (if you assign a value in declaration to a variable other than '0' you will see that that will actually require some of your progmem)
I suspect that the optimizer does something unexpected, and as i said before i would just call .begin() from setup() or from a function called from setup() that also initializes the variables that i want to assign return values from other functions to. Just to make sure that things will happen in the order i want them to. setup() is the last function to be called before

while(1) {
  loop();
  yield():
}