I'm certainly aware there is no built-in error detection. I would like to find out and write my own. If it is as you suggest - the whole sector becomes bad, then there is no practical remedy. If its only certain locations in the sector as I suspect, then I can/will write some avoidance code.
However, on the slowing down... I thought and read the same as you; however, this appears to be mistaken. The flash chip on this ESP8266 - ESP01 IS slowing down due to use. The attached graph is the on-going test. Unless... you can suggest some other influence in the attached test code to make it look like its slowing down.
#include <spi_flash.h>
#include <user_interface.h>
#define EEPROM_OFFSET -5
const u16 MAX = SPI_FLASH_SEC_SIZE; // in Bytes
u32 array[MAX / sizeof(u32)];
u16 sector;
u32 location;
u32 count;
void check(SpiFlashOpResult rslt, const char* msg)
{
if (rslt != SPI_FLASH_RESULT_OK)
{
Serial.printf("%s[%u] error = %u\n", msg, count, rslt);
while(true) delay(1000);
}
}
u16 mapSector(s16 sectorOffset)
{
// If sectorOffset >= 0, we are doing relative to the beginning.
// If sectorOffset < 0, we are doing realtive to the end.
// Last 4 sectors are System.
// 5th back from end is "EEPROM" area.
u32 sec;
flash_size_map map = system_get_flash_size_map();
switch (map)
{
case FLASH_SIZE_4M_MAP_256_256: sec = 128; break;
case FLASH_SIZE_2M: sec = 0; break;
case FLASH_SIZE_8M_MAP_512_512: sec = 256; break;
case FLASH_SIZE_16M_MAP_512_512: sec = 512; break;
case FLASH_SIZE_32M_MAP_512_512: sec = 1024; break;
case FLASH_SIZE_16M_MAP_1024_1024: sec = 512; break;
case FLASH_SIZE_32M_MAP_1024_1024: sec = 1024; break;
case FLASH_SIZE_64M_MAP_1024_1024: sec = 2048; break;
case FLASH_SIZE_128M_MAP_1024_1024: sec = 4096; break;
}
if (sectorOffset < 0)
sectorOffset = sec + sectorOffset;
return sectorOffset;
}
void setup()
{
Serial.begin(115200);
while(!Serial) { Serial.print("."); delay(100); }
delay(2000);
Serial.println("\nStarting ------------------------ ");
sector = mapSector(EEPROM_OFFSET);
location = sector * SPI_FLASH_SEC_SIZE;
check(spi_flash_read(location, array, MAX), "Init Read");
count = array[0];
if (count > (u32)-10)
count = 0;
Serial.printf("Test starts at %u\n", count);
Serial.println("Started");
}
#define INTERVAL 3600000
void loop()
{
static u32 loops = 0;
loops++;
static u32 last = millis();
u32 now = millis();
if (now - last > INTERVAL)
{
u32 div = INTERVAL / 1000;
Serial.printf("Count=%u Rate=%f\n", count, (float)loops / (float)div);
last = now;
loops = 0;
}
count++;
// Erase It
check(spi_flash_erase_sector(sector), "Erase");
// Write It
for(int i=0; i<MAX / sizeof(u32); i++)
array[i] = count;
check(spi_flash_write(location, array, MAX), "Write");
// Read It Back In
check(spi_flash_read(location, array, MAX), "Read");
// Check It
SpiFlashOpResult rslt = SPI_FLASH_RESULT_OK;
for(int i=0; i<MAX / sizeof(u32); i++)
{
if (array[i] != count)
{
if (rslt == SPI_FLASH_RESULT_OK)
Serial.printf("Verification[%u]\n", count);
Serial.printf("Memory error @ %u\n", i);
rslt = SPI_FLASH_RESULT_ERR;
}
}
check(rslt, "Valid");
}
w/ GUI Admin Client, Drag & Drop File Manager, OTA Built-In, Access Point Manager,
Performance Metrics, Web Socket Comms, App API, All running on ESP8266...
Even usable on ESP-01S --- Please check it out!
https://inqonthat.com/inqportal-the-three-line-promise/
https://InqOnThat.com/inqportal