Ошибка при работе EEPROM и deepSleep

Sergey_C

✩✩✩✩✩✩✩
23 Фев 2024
11
3
Здравствуйте.
При использовании EEPROM с модулем NodeMCU периодически сбрасывается сохраненное значение в ячейке памяти после очередного пробуждения модуля от сна. Некоторое время все работает нормально, счетчик с переменной N увеличивается, но в какой-то момент (обычно более 100 пробуждений) счетчик сбрасывается в 0. Один раз сбросился в -1. После того как сбросится, значение в памяти начинает скакать вверх-вниз при каждом пробуждении. Заливаю скетч в модуль, все начинает работать нормально некоторое время.
Прошу прощения за длинный код, специально не стал обрезать лишнее, вдруг в этом причина. На рисунке ситуация после сброса счетчика в памяти. Параллельно вывожу информацию на дисплей, там такие же ошибочные значения счетчика. Подскажите, пожалуйста, что не так?
График.jpg


C++:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <EEPROM.h>
#include <GyverOLED.h>

GyverOLED<SSD1306_128x64, OLED_NO_BUFFER> oled;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
WiFiClient client;

const char* mySSID = "****";
const char* mySSIDpass = "*****";
char thingSpeakAddress[] = "api.thingspeak.com";
String writeAPIKey = "****";

int n, k, l, l1, l2;
int Time = 900000000;
IPAddress ip(192,168,0,37);     
IPAddress gateway(192,168,0,1);   
IPAddress subnet(255,255,255,0);   
IPAddress dns1(77,88,8,8);
IPAddress dns2(8,8,8,8);

void setup()
{ 
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet, dns1, dns2);
  WiFi.disconnect();
  delay(100);
  WiFi.begin(mySSID, mySSIDpass);
  oled.init();       
  oled.clear();       
  oled.setScale(2);   
  oled.setContrast(5);
  oled.home();   
  Serial.begin(74880);
  EEPROM.begin(256); 
 /*k = 0;   Первоначальная инициализация счетчиков
 l = 0;
 l1 = 0;
 l2 = 0;
 EEPROM.put(10, k);
 EEPROM.put(20, l);
 EEPROM.put(30, l1);
 EEPROM.put(40, l2);
 EEPROM.commit();*/
  EEPROM.get(10, k);
  EEPROM.get(20, l);
  EEPROM.get(30, l1);
  EEPROM.get(40, l2);
  n = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
        delay(500);     
    oled.print(".");   
    n++;
    if (n > 60)
    {     
      l++;    //Увеличение счетчика ошибок при подключении к WiFi
      oled.clear(); 
      oled.home();   
      oled.print("Error WiFi"); 
      EEPROM.put(20, l);
      EEPROM.commit();
      delay(1000);   
      ESP.deepSleep(Time);         
    }
    }     
  oled.clear(); 
  oled.home();
  oled.print("Connect"); 
  oled.setCursor(0, 2);
  String s = String(k) + " " + String(l) + " " + String(l1) + " " + String(l2);
  oled.print(s);   
  timeClient.begin();
  timeClient.setTimeOffset(10800); 
  delay(100); 
}

void loop()
{   
  timeClient.update();
  int currentHour = timeClient.getHours();
  int currentMinute = timeClient.getMinutes();
  String s;
  if (currentHour < 10) s = "0" + String(currentHour);
  else s = String(currentHour);
  if (currentMinute < 10) s = s + ":" + "0" + String(currentMinute);
  else s = s + ":" + String(currentMinute);
  EEPROM.get(10, k); 
  k++;  //Увеличение счетчика удачных подключени к WiFi
  EEPROM.put(10, k);
  EEPROM.commit(); 
  updateThingSpeak("field5=" + String(k));
  delay(5000);
  oled.setCursor(0, 6); 
  oled.print(s);   
  delay(100);
  ESP.deepSleep(Time);
}

void updateThingSpeak(String tsData)
{ 
  if (client.connect(thingSpeakAddress, 80))
  {   
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");   
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(tsData.length());
    client.print("\n\n");
    client.print(tsData);   
    if (client.connected())
    {         
      oled.setCursor(0, 4);
      oled.print("update th");
    }
    else
    {           
      oled.setCursor(0, 4);
      oled.print("error th");
      l2++;  //Увеличение счетчика ошибок при обновлениии данных на сайте
      EEPROM.put(40, l2);   
      EEPROM.commit();   
    }
  }
  else
  {       
    oled.setCursor(0, 4);
    oled.print("error th");
    l2++;   //Увеличение счетчика ошибок при обновлениии данных на сайте
    EEPROM.put(40, l2);   
    EEPROM.commit();
  }
}
 

Вложения

Сотнег

★★★★★★★
15 Янв 2020
4,357
1,493
@Sergey_C,
не увидел в коде обход вочдога.
Как-то слишком самоуверенно пытаться 60 раз подключиться к вайфаю с паузой в секунду,
если плата работает только 8 секунд.
 

Sergey_C

✩✩✩✩✩✩✩
23 Фев 2024
11
3
@Геннадий П, Да, стандартную.

@Сотнег, Поясните, пожалуйста, на счет вотчдога. При программировании Arduino его необходимо было активировать. На ESP он работает по умолчанию? Если да, то как он связан с ошибкой в EEPROM?
На этой плате ни разу не было 60 неудачных попыток подключений, поэтому ничего сказать не могу. На другой плате ESP-01 использовал этот блок кода подключения и счетчик иногда доходил до 60 попыток неудачного подключения и плата успешно засыпала
 

Сотнег

★★★★★★★
15 Янв 2020
4,357
1,493
@Sergey_C,
да, на ESP8266 он включен.
Возможно, плата у вас перезагружается в момент записи в EEPROM.

@Sergey_C,
может быть, это очередной баг новых версий ядра платы?
2.7.4 была стабильной, потом стало плохо.

Или просто у вас на плате память бракованная.
 

Sergey_C

✩✩✩✩✩✩✩
23 Фев 2024
11
3
@Сотнег, Тоже думаю про брак, так как на модуле ESP-01 похожий код работает без проблем.

Про сторожевой таймер не знал, спасибо. Но похоже его все таки нужно активировать.
Модифицировал код, установив порог в 1000 попыток и выведя на экран счетчик попыток. Отключил роутер. На 500 попытке устал ждать, включил роутер и плата спокойно подключилась. Никаких перезагрузок через 8 секунд.
Да и на других платах ни разу не было перезагрузок при невозможности подключения как минимум в течение 30 секунд.
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,966
632
44
Тоже думаю про брак, так как на модуле ESP-01 похожий код работает без проблем.
Сколько в целом с данным кодом проработал модуль ЕСП, на котором идет сбой?

Дело в том, что в ЕСП все действия ЕЕПРОМ эмулируются записью во флеш-память. И на сколько известно, стандартная библиотека не работает по кольцевой записи. А если посчитать, то у вас примерно одна запись в 10 минут, а это примерно 150 записей в сутки. И примерно 10тыс ресурса перезаписей одной ячейки хватит примерно на 2 месяца непрерывной работы.
Или как вариант, попробовать сдвинуть адреса записи в ЕЕПРОМ.
 

vortigont

★★★★★★✩
24 Апр 2020
1,022
541
Saint-Petersburg, Russia
не по теме еепром, но судя по скетчу вам еепром там вообще не нужен. Сохраняйте свой счетчик в RTC память и не упиливайте флеш. пример