PlatformIO Community

Atom+PIO Esp8266 Eeprom.write problem

Hi, I have problem with programming Esp826 EEprom with this code (taken from Arduino IDE example).
What is interesting - this code works fine on Arduino IDE but nothing is stored in Eeprom (when program running) when firmware was uploaded by Atom with PIO. What should I do addtionally in Atom(PIO) settings/config_file or in code ?
Thanks!
/Baxoza


#include "EEPROM.h"
#include "Arduino.h"   <------ added to let PIO compile successfully

int addr = 0;

void setup() {
  Serial.begin(115200);
  EEPROM.begin(4);
}

void loop() {
  int val = addr;
  EEPROM.write(addr, val);
  addr = addr + 1;
  
  if (addr == 5) {
    addr = 0;
    EEPROM.commit();
    Serial.print("Done...");
    delay(10000);
  }

  delay(100);
  Serial.print(addr);
  Serial.print("\t");
  Serial.print(val);
  Serial.println();
}

I’m facing exactly the same problem. Got no solution so far.

Please state the output from the working program, the output from the not working program and the platformio.ini, as well as the code if it differs from the one above.

Hi, currently I added the EEPROM feature in a bigger project, than an .ino file, with multiple modules, written by me. I need to transfer data in binary, and then debug it with a logic analyzer, or oscilloscope, so I can’t really show the output. What is happening, is that a read operation returns empty data from the EEPROM. If I write something before reading the same address, I get the desired data. So, both operations are working independently, maybe the memory is wiped somehow at build, this is why I can’t read datas from previous sessions.

Here’s how I read and write multiple bytes:

void readEEPROM(char * target, uint8_t address_lu8, uint8_t addressSize_lu8) {
   uint8_t addressCounter_lu8;
   for(addressCounter_lu8 = 0; addressCounter_lu8 < addressSize_lu8; addressCounter_lu8++) {
      *(target + addressCounter_lu8)  = EEPROM.read(address_lu8 + addressCounter_lu8);
   }
}

void writeEEPROM(char* value, uint8_t address_lu8, uint8_t addressSize_lu8) {
  uint8_t addrCounter_lu8;
  for (addrCounter_lu8 = 0; addrCounter_lu8 < addressSize_lu8; addrCounter_lu8++) {
        EEPROM.write((address_lu8 + addrCounter_lu8), *(value + addrCounter_lu8));
  }
  EEPROM.commit();
}

platformio.ini:

[env:esp8266]
platform = espressif8266
board = esp12e
framework = arduino
lib_ignore = FreeRTOS
lib_deps =
    ESP8266WiFi
    EEPROM
    WiFiUdp
    WifiManager
    WebSockets
    ArduinoJson
    AsyncMqttClient

Thank you for you support.

Aha, so the problem is not

but the saved values do not survive a re-flash of the firmware. As the documentation says “EEPROM” is emulated by the ESP8266 by implementing it as flash read/writes on its internal flash. Reading the source however it should re-read the previous contents of the flash in the .begin() method in RAM, and then at a write(), the whole new sector is written to flash again. One explanation for this behaviour is of course that a flash either erases the chip or overwrites the EEPROM flash sector. I’ll look into it.

Due to its speed compared to SPIFFS (haven’t tried yet), I would stay by EEPROM. I am 100% sure my program worked / previous contents were stored in memory earlier (6 months or so). Erasing content at re-flash can be solved with a simple verification, and storing some default values at the beginning.
If you have any news/progress in this case, let me know.

I can’t reprodue your problem. I’ve written this EEPROM helper to help dump, read, write and erase the flash.

#include <Arduino.h>
#include <ESP.h>
#include <EEPROM.h>

String userInput;

/* imitate logic from EEPROM.cpp */
extern "C" uint32_t _SPIFFS_end;
uint32_t eeprom_sector = (((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE);
const int _size = 4;
uint8_t _data[_size];

void hexDump (const char *desc, const void *addr, const int len);

void setup() {
	Serial.begin(115200);
	printf("\nEEPROM Helper start. EEPROM sector at 0x%08x, end of SPIFFS at 0x%08x\n", (unsigned)eeprom_sector, (unsigned)&_SPIFFS_end);
	//use only first 4 bytes/ 1 flash word
	EEPROM.begin(_size);
}

void dumpFlash() {
	memset(_data, 0, _size);
	ESP.flashRead(eeprom_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size);
	hexDump("Flash data", _data, _size);
}

void loop() {
	if(Serial.available()) {
		userInput = Serial.readString();
		userInput.trim();

		if(userInput == "dump") {
			dumpFlash();
		} else if(userInput == "write") {
			EEPROM.write(0, 0x01);
			EEPROM.write(1, 0x02);
			EEPROM.write(2, 0x03);
			EEPROM.write(3, 0x04);
			EEPROM.commit();
			Serial.println("Wrote 1..4 into addresses 0..3");
		} else if(userInput == "read") {
			for(int i=0; i < 4; i++) {
				printf("EEPROM[%d] = 0x%02x\n", i, (int)EEPROM.read(i));
			}
		} else if(userInput == "erase") {
			EEPROM.end();
			printf("Erasing sector 0x%08x\n", eeprom_sector);
			ESP.flashEraseSector(eeprom_sector);
			//re-begin EEPROM otherwise old contents are still in RAM
			EEPROM.begin(_size);
		} else {
			Serial.print ("Unknown command: ");
			Serial.println(userInput);
		}
	}
}

void hexDump (const char *desc, const void *addr, const int len) {
    int i;
    unsigned char buff[17];
    const unsigned char *pc = (const unsigned char*)addr;

    // Output description if given.
    if (desc != NULL)
        printf ("%s:\n", desc);

    if (len == 0) {
        printf("  ZERO LENGTH\n");
        return;
    }
    if (len < 0) {
        printf("  NEGATIVE LENGTH: %i\n",len);
        return;
    }

    // Process every byte in the data.
    for (i = 0; i < len; i++) {
        // Multiple of 16 means new line (with line offset).

        if ((i % 16) == 0) {
            // Just don't print ASCII for the zeroth line.
            if (i != 0)
                printf ("  %s\n", buff);

            // Output the offset.
            printf ("  %04x ", i);
        }

        // Now the hex code for the specific character.
        printf (" %02x", pc[i]);

        // And store a printable ASCII character for later.
        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
            buff[i % 16] = '.';
        else
            buff[i % 16] = pc[i];
        buff[(i % 16) + 1] = '\0';
    }

    // Pad out last line if not exactly 16 characters.
    while ((i % 16) != 0) {
        printf ("   ");
        i++;
    }

    // And print the final ASCII bit.
    printf ("  %s\n", buff);
}

with platformio.ini

[env:esp8266]
monitor_speed = 115200
platform = espressif8266
board = nodemcuv2
framework = arduino

I test it as follows:

  1. erase the chip
  2. use the dump command to make sure the flash is erased (must read as 0xff..
  3. write in EEPROM
  4. read back EEPROM
  5. reflash the firmware
  6. read back EEPROM

The test result is that EEPROM data is preserved upon reflashes. Output

C:\Users\Maxi>"C:\Program Files (x86)\Python35\Scripts\miniterm.py" --echo --exit-char=50 COM12 115200
--- Miniterm on COM12  115200,8,N,1 ---
--- Quit: '2' | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
EEPROM Helper start. EEPROM sector at 0x000003fb, end of SPIFFS at 0x405fb000
dump
Flash data:
  0000  ff ff ff ff                                      ....
read
EEPROM[0] = 0xff
EEPROM[1] = 0xff
EEPROM[2] = 0xff
EEPROM[3] = 0xff
write
Wrote 1..4 into addresses 0..3
dump
Flash data:
  0000  01 02 03 04                                      ....
read
EEPROM[0] = 0x01
EEPROM[1] = 0x02
EEPROM[2] = 0x03
EEPROM[3] = 0x04

--- exit ---

<reflash using "PlatformIO upload" task>

C:\Users\Maxi>"C:\Program Files (x86)\Python35\Scripts\miniterm.py" --echo --exit-char=50 COM12 115200
--- Miniterm on COM12  115200,8,N,1 ---
--- Quit: '2' | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
EEPROM Helper start. EEPROM sector at 0x000003fb, end of SPIFFS at 0x405fb000
dump
Flash data:
  0000  01 02 03 04                                      ....
read
EEPROM[0] = 0x01
EEPROM[1] = 0x02
EEPROM[2] = 0x03
EEPROM[3] = 0x04

--- exit ---

So, did I understand the problem correctly that this is exactly what shouldn’t happen, i.e. after a reflash data is destroyed? Also with what exact platformio.ini are you working? Do you have a minimal example for problem reproduction?

It’s very strange I’ve tried your code, here’s the Output:

> Executing task in folder EEPROM TEST:     C:\Users\adam.ambarus\.platformio\penv\Scripts\platformio.exe device monitor <

--- Miniterm on COM10  115200,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
EEPROM[0] = 0x00
EEPROM[1] = 0x00
EEPROM[2] = 0x00
EEPROM[3] = 0x00
Wrote 1..4 into addresses 0..3
EEPROM[0] = 0x01
EEPROM[1] = 0x02
EEPROM[2] = 0x03
EEPROM[3] = 0x04
␀rd␀l���␂�$�|␂␌␄␌�␌$�␄c|��␂�␓��|    ␛cl␄#��oN�␀$on���␌b␜p␌db␏l{lp�o�␐␂␌␄�␄l␄��␌␄␌B␌o�|    ␂l�␌␄�p␄��no�␃$��l ␃�2␓on␄l     ␂␏␂n{�ےn␄␌b␌�␎l␎s���␃␌␄c␄�␎l�␂�p�l$�␒�$`␂��N�␂

EEPROM Helper start. EEPROM sector at 0x000003fb, end of SPIFFS at 0x405fb000
EEPROM[0] = 0x00
EEPROM[1] = 0x00
EEPROM[2] = 0x00
EEPROM[3] = 0x00

You can see where I restarted the the ESP, but the data was not preserved at all, even after a restart.

I’m working with this type of chip, so I changed the board = esp07.

Wait so just even pressing the Reset button on the board makes it loose the EEPROM content? You did not reflash it?

Then we might have a general configuration problem for SPIFFS/EEPROM flash addresses for the ESP07 module, which, according to the datasheet, has 1MB flash chip as compared to the 4MB of my NodeMCUv2 (ESP-12E). Most interestingly we’re using the same addreses for the end-of-spiffs and EEPROM sector number, although these addresses should be different if my flash is bigger than yours. I’ll recheck the memory map; still the answer to the question above would be very important

Edit: Oh and one thing: Can you flash the main.cpp code in the Arduino IDE? Is the behaviour different then, or the addresses? Also a screenshot for the “Tools” menu of the Arduino IDE with all the configuration settings for the board would be good.

Definitely makes it loose. Sadly, I can’t make further tests in the upcoming weekend.

Blockquote[quote=“maxgerhardt, post:9, topic:2730”]
Edit : Oh and one thing: Can you flash the main.cpp code in the Arduino IDE? Is the behaviour different then, or the addresses? Also a screenshot for the “Tools” menu of the Arduino IDE with all the configuration settings for the board would be good.
[/quote]

It works in Arduino IDE, but there are differences between the addresses. here’s the Tools menu, and the Serial Output (copy-paste just doesn’t work):

Okay that’s a very strong hint. Let’s first try to check whether PIO also does the 512K flashsize + 65K SPIFFS.

Eh… on second thought, why 512K flashsize? As I linked in the datasheet above, it says

Does the resul change when you put Flash size to 1MB? If it doesn’t, we have a case of “your chip has only 512K flash but we see it as a 1MB one and write to memory that isn’t there”

At build, I always get a message, like Auto-detected Flash size: 512KB. Right now, in Arduino IDE I chose 1M Flash Size (no SPIFFS), and does not work anymore.

Okay then in PIO do the following. Add (docs)

build_flags = -Wl,-Teagle.flash.512k64.ld

to the platformio.ini.

Does the PlatformIO firmware work now?

YES, it does! It persists the data after both restart and reflash. Here’s how my .ini file looks:

[env:esp8266]
monitor_speed = 115200
platform = espressif8266
board = esp12e
build_flags =  -Wl,-Teagle.flash.512k64.ld
framework = arduino

Thank you!

In the future I want to use SPIFFS too. Will this configuration affect it? (I already get a message, like: spiffs.bin (length 1028096) at offset 3145728 will not fit in 524288 bytes of flash. Use --flash-size argument, or change flashing address)

Hallelujah! So it seems than that you have gotten a 512K “ESP-07” although it’s clearly declared to be a 1MB flash size version… very weird. So PIO’s board definition is correct by the means of datasheet…

The SPIFFS data size seems to be 1004KB (nearly 1MB) but the linker script allocates at max a 64K of the available 512K for it, so this is impossible to fit oO. Does this already occur with an empty data/ directory, aka actually no files for in the SPIFFS? I’m not sure if this nearly 1MB SPIFFS is a side-effect of some old / non-updated info in the esp board size though.

Could you for the fun of try a simple

board = esp01

with no build_flags? The board definition seems to match your ESP pretty well…

Cool, so I really have to pay attention to this in the future.

Wow, the “Upload file system image” command worked with empty data folder, and then even with the html file in it.

Yes, it works!

So in conclusion about EEPROM, I have to look more careful what chip we have, can’t trust any datasheet. Thanks the support!

Then this was just a case that the previously generated spiffs.bin (which was generated with 1MB SPIFFS setting) was still there and was tried to be uploaded. You solved this be regenerating the file by executing that task. (Also “Clean Project” task should have done it I guess).

Exactly. Let’s conclude this topic with “If the used linker script / board identifier uses a different flash size than what is actually connected to the ESP8266, writes to the EEPROM might lead to nowhere and not be saved persistently. The usable linker scripts can be viewed in the documentation and the JSON description of each board.”