ESP8266 crashes after (a lot of) time zone changes

Hi,

I’m working on a World clock development with an ESP8266. But my code is always crashing after a while. I used as the basis for my development the NTP-TZ-DST example.

I condensed my code to force the issue, after about 114 to 127 cycles the system is crashing.

I like to know if I do not understand the time functions correctly or if there is a memory leak in the time(zone) management.

While I try and error for a while now, I would be happy to get help here.
Thanks for your support.

Jens

#include <TZ.h>
#include <ESP8266WiFi.h>
#include <coredecls.h>                  // settimeofday_cb()
#include <Schedule.h>
#include <PolledTimeout.h>

#include <time.h>                       // time() ctime()
#include <sys/time.h>                   // struct timeval

#include <sntp.h>                       // sntp_servermode_dhcp()

// for testing purpose:
extern "C" int clock_gettime(clockid_t unused, struct timespec *tp);

static timeval tv;
static timespec tp;
static time_t now;
bool   NTP_Time_is_set;

void Debug(String Text);
String Left(String Text,int len);
String Get_Time_Zone(int TZ_Number);
void NTP_time_is_set_scheduled();
String NTP_Time_Text(String TimeZone);

void Debug( String Text)
{
    String NTP_Time_Text = NTP_Get_Time(TZ_Europe_Berlin) + ":" + Text;
    Serial.println(NTP_Time_Text);
}

String Left(String Text,int len)
{
  Text = Text.substring(Text.length()-len, Text.length());
  return Text;
}

String Get_Time_Zone(int TZ_Number)
{
  switch (TZ_Number) 
  {
    case 0:
      return TZ_Europe_Berlin;
    break;
    case 1:
      return TZ_Europe_London;
    break;      
    case 2:
      return TZ_America_New_York;
    break;
    case 3:
      return TZ_America_New_York;
    break;
    case 4:
      return TZ_America_Chicago;
    break;
    case 5:
      return TZ_America_Los_Angeles;
    break;
    case 6:
      return TZ_Asia_Kolkata;
    break;
    case 7:
      return TZ_Australia_Sydney;
    break;
    case 8:
      return TZ_Asia_Manila;
    break;
  }
}

void NTP_time_is_set_scheduled()
{
  NTP_Time_is_set = true;
  Debug("NTP was updated");
  for(int i = 0 ; i <= 1000; i++)
    for(int j = 0 ; j <= 8; j++)
      Debug(Left("0000" + String(i),4) + ":" + String(j) + ":" + NTP_Get_Time(Get_Time_Zone(j)));
}

String NTP_Get_Time(String TimeZone)
{
  String Time_Return;
  if(NTP_Time_is_set == true)
  {
    char TimeZoneBuffer[100];
    TimeZone.toCharArray(TimeZoneBuffer, 99);
    setenv("TZ", TimeZoneBuffer, 1);
    tzset();
    gettimeofday(&tv, nullptr);
    clock_gettime(0, &tp);
    now = time(nullptr);
    const tm* tm = localtime(&now);
    Time_Return = Left("00" + String(tm->tm_hour),2) + ":" + Left("00" + String(tm->tm_min),2) + ":" + Left("00" + String(tm->tm_sec),2);
  }
  else
    Time_Return = Left("00000000" + String(millis()),8);
  return Time_Return;
}

void setup() {
  Serial.begin(115200);
  Debug("Setup NTP...");
  time_t rtc = 0;
  timeval tv = { rtc, 0 };
  settimeofday(&tv, nullptr);
  settimeofday_cb(NTP_time_is_set_scheduled);
  configTime(0, 0, "fritz.box","192.168.100.254","pool.ntp.org");
  gettimeofday(&tv, nullptr);
  clock_gettime(0, &tp);
  now = time(nullptr);
  setenv("TZ", "UTC0", 1);
  Debug("Setup NTP Done");
  Debug("Time is currently set by a constant.");
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin("testwifi","1234567890abcdef");
}

void loop() {
  yield();
}

You can try the printing the results of the [

ESP.getFreeHeap()

](Arduino/Esp.cpp at ce200ed72e5511d89d92998065df879f0cfcd6aa · esp8266/Arduino · GitHub) and [

ESP.getMaxFreeBlockSize()

](Arduino/Esp.cpp at ce200ed72e5511d89d92998065df879f0cfcd6aa · esp8266/Arduino · GitHub) functions. If it's a memory leak, the free heap memory and the maximum free block size both go down, if it's memory fragmentation without a leak, only the maximum free block size goes down.

What error message does it show in the Serial monitor? Just a WDT reset, or an exception with a stack trace? In case of the latter, did you try to decode the stack trace?

Pieter

Maybe it’s your 8,000 String concatenations… oops sorry, your 9,009 String concatenations…

  for(int i = 0 ; i <= 1000; i++)
    for(int j = 0 ; j <= 8; j++)
      Debug(Left("0000" + String(i),4) + ":" + String(j) + ":" + NTP_Get_Time(Get_Time_Zone(j)));

Maybe it’s your 8,000 String concatenations… oops sorry, your 9,009 String concatenations…

Hi,

I changed the code and deleted all outputs and String functions (exept the TZ selection) and its still crashes

Exception (29):
epc1=0x4000df64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

>>>stack>>>

ctx: sys
sp: 3fffec10 end: 3fffffb0 offset: 0190
3fffeda0:  3fffee60 3ffed718 00000002 4010027c  
3fffedb0:  40221403 00000000 00000020 40221398  
.....
3fffffa0:  feefeffe feefeffe 3ffee4ac 40202684  
<<<stack<<<

last failed alloc call: 40206D90(9)

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 3456, room 16 
tail 0
chksum 0x84
csum 0x84
va5432625
~ld
Exception 29: StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores
PC: 0x4000df64
EXCVADDR: 0x00000000
Memory allocation of 9 bytes failed at 0x40206d90: _setenv_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdlib/setenv_r.c line 120

Decoding stack results
0x4010027c: pvPortZalloc(size_t, char const*, int) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\heap.cpp line 301
0x40100968: malloc(size_t) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\umm_malloc\umm_malloc.cpp line 511
0x402165e4: mem_malloc at core/mem.c line 210
0x4020cfa1: do_memp_malloc_pool at core/memp.c line 255
0x40203074: std::_Function_base::_Base_manager ::_M_manager(std::_Any_data &, const std::_Any_data &, std::_Manager_operation) at c:\users\Test\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\2.5.0-4-b40a506\xtensa-lx106-elf\include\c++\4.8.2/functional line 1931
0x4020de35: sys_untimeout_LWIP2 at core/timeouts.c line 337
0x4021643c: sntp_recv at apps/sntp/sntp.c line 520
0x402024dc: loop_task(ETSEvent*) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\core_esp8266_main.cpp line 205
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\core_esp8266_main.cpp line 177
0x4020b482: _strtoul_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdlib/strtoul.c line 166
0x4020bf02: _scanf_i at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf_i.c line 173
0x4020b9d5: __ssvfscanf_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 355
0x4020bc88: __ssvfscanf_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 469
0x4020bfb5: _scanf_i at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf_i.c line 218
0x4020bc10: __ssvfscanf_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 446
0x4020b3dc: _strtoul_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdlib/strtoul.c line 140
0x4020bc10: __ssvfscanf_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 446
0x4020bfb5: _scanf_i at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf_i.c line 218
0x4020b3dc: _strtoul_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdlib/strtoul.c line 140
0x4020bc10: __ssvfscanf_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 446
0x4020b800: _sungetc_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 221
0x4020b890: __ssrefill_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 269
0x4020b800: _sungetc_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 221
0x4020b890: __ssrefill_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/nano-vfscanf.c line 269
0x4020b328: __seofread at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/stdio.c line 73
0x4020b26c: sscanf at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/sscanf.c line 431
0x4020b328: __seofread at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/stdio/stdio.c line 73
0x40100968: malloc(size_t) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\umm_malloc\umm_malloc.cpp line 511
0x402084a8: _tzset_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/time/tzset_r.c line 203
0x40203301: _gettimeofday_r(_reent*, timeval*, void*) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\time.cpp line 127
0x40203264: clock_gettime(clockid_t, timespec*) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\time.cpp line 72
0x40205a64: localtime_r at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/time/lcltime_r.c line 126
0x4020584c: localtime at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/time/lcltime.c line 60
0x40201130: NTP_Get_Time(String) at C:\Users\Test\Documents\Arduino\NTP_TEST/NTP_TEST.ino line 100
0x40208726: memmove_P at /home/earle/src/esp-quick-toolchain/repo/newlib/newlib/libc/sys/xtensa/string_pgmspace.c line 187
0x402022ec: String::copy(char const*, unsigned int) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\WString.cpp line 214
0x40100694: umm_free_core(void*) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\umm_malloc\umm_malloc.cpp line 316
0x40100694: umm_free_core(void*) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\umm_malloc\umm_malloc.cpp line 316
0x40100933: free(void*) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\umm_malloc\umm_malloc.cpp line 362
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\core_esp8266_main.cpp line 177
0x40203f8c: run_scheduled_recurrent_functions() at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\Schedule.cpp line 230
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\core_esp8266_main.cpp line 177
0x402025a2: __yield() at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\core_esp8266_main.cpp line 112
0x4020126c: loop() at C:\Users\Test\Documents\Arduino\NTP_TEST/NTP_TEST.ino line 124
0x40202684: loop_wrapper() at C:\Users\Test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.1\cores\esp8266\core_esp8266_main.cpp line 197

If you modified the code, please post the updated code.

Hi,

Here is the updated code without the Outputs, But it still crashes

#include <TZ.h>
#include <ESP8266WiFi.h>
#include <coredecls.h>                  // settimeofday_cb()
#include <Schedule.h>
#include <PolledTimeout.h>

#include <time.h>                       // time() ctime()
#include <sys/time.h>                   // struct timeval

#include <sntp.h>                       // sntp_servermode_dhcp()

// for testing purpose:
extern "C" int clock_gettime(clockid_t unused, struct timespec *tp);

static timeval tv;
static timespec tp;
static time_t now;
bool   NTP_Time_is_set;

//void Debug(String Text);
String Left(String Text,int len);
String Get_Time_Zone(int TZ_Number);
void NTP_time_is_set_scheduled();
void NTP_Time_Text(String TimeZone);

//void Debug( String Text)
//{
//    String NTP_Time_Text = NTP_Get_Time(TZ_Europe_Berlin) + ":" + Text;
//    Serial.println(NTP_Time_Text);
//}

//String Left(String Text,int len)
//{
//  Text = Text.substring(Text.length()-len, Text.length());
//  return Text;
//}

String Get_Time_Zone(int TZ_Number)
{
  switch (TZ_Number) 
  {
    case 0:
      return TZ_Europe_Berlin;
    break;
    case 1:
      return TZ_Europe_London;
    break;      
    case 2:
      return TZ_America_New_York;
    break;
    case 3:
      return TZ_America_New_York;
    break;
    case 4:
      return TZ_America_Chicago;
    break;
    case 5:
      return TZ_America_Los_Angeles;
    break;
    case 6:
      return TZ_Asia_Kolkata;
    break;
    case 7:
      return TZ_Australia_Sydney;
    break;
    case 8:
      return TZ_Asia_Manila;
    break;
  }
}

void NTP_time_is_set_scheduled()
{
  NTP_Time_is_set = true;
//  Debug("NTP was updated");
  for(int i = 0 ; i <= 1000; i++)
    for(int j = 0 ; j <= 8; j++)
      //Debug(Left("0000" + String(i),4) + ":" + String(j) + ":" + 
      NTP_Get_Time(Get_Time_Zone(j));
}

void NTP_Get_Time(String TimeZone)
{
//  String Time_Return;
  if(NTP_Time_is_set == true)
  {
    char TimeZoneBuffer[100];
    TimeZone.toCharArray(TimeZoneBuffer, 99);
    setenv("TZ", TimeZoneBuffer, 1);
    tzset();
    gettimeofday(&tv, nullptr);
    clock_gettime(0, &tp);
    now = time(nullptr);
    const tm* tm = localtime(&now);
    //Time_Return = Left("00" + String(tm->tm_hour),2) + ":" + Left("00" + String(tm->tm_min),2) + ":" + Left("00" + String(tm->tm_sec),2);
  }
//  else
   // Time_Return = Left("00000000" + String(millis()),8);
//  return Time_Return;
}

void setup() {
  Serial.begin(115200);
//  Debug("Setup NTP...");
  time_t rtc = 0;
  timeval tv = { rtc, 0 };
  settimeofday(&tv, nullptr);
  settimeofday_cb(NTP_time_is_set_scheduled);
  configTime(0, 0, "fritz.box","192.168.100.254","pool.ntp.org");
  gettimeofday(&tv, nullptr);
  clock_gettime(0, &tp);
  now = time(nullptr);
  setenv("TZ", "UTC0", 1);
//  Debug("Setup NTP Done");
//  Debug("Time is currently set by a constant.");
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin("Helloagain","12345678901234567890");
}

void loop() {
  // put your main code here, to run repeatedly:
  yield();
}

I have the feeling that the issue is inside this code, where I do not have a clue if it is correct ( I only copied from the example ):

    setenv("TZ", TimeZoneBuffer, 1);
    tzset();
    gettimeofday(&tv, nullptr);
    clock_gettime(0, &tp);
    now = time(nullptr);
    const tm* tm = localtime(&now);

If someone knows where to find an exelant description on the time, time zone and NTP topic, all I found are examples but without description.

rst cause:2, boot mode:(3,7)This means that the reset has an external cause Reset causes so that is where you should look.