Getting an ESP exception 9 when updating from NTP Client

0

My current project is one of these WordClocks built with WS2812B LEDs and an ESP8266 and it works great so far. The only problem I have is with the NTP Client library (https://github.com/arduino-libraries/NTPClient). My sketch syncs the RTC time every 30min with the NTP server but sometimes it throws an exception 9 during timeClient.update(). This is the decoded exception:

PC: 0x402059f9: NTPClient::sendNTPPacket() at /Users/janik/Documents/Arduino/libraries/NTPClient/NTPClient.cpp line 172
EXCVADDR: 0x3ffee9ff

Decoding stack results
0x4010095a: millis() at /Users/janik/Library/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/cores/esp8266/core_esp8266_wiring.cpp line 188
0x40205a45: NTPClient::forceUpdate() at /Users/janik/Documents/Arduino/libraries/NTPClient/NTPClient.cpp line 76
0x40205ae7: NTPClient::update() at /Users/janik/Documents/Arduino/libraries/NTPClient/NTPClient.cpp line 99
0x4020113e: updatetime() at /Users/janik/Documents/Arduino/WordClock/WordClock.ino line 44
0x4010095a: millis() at /Users/janik/Library/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/cores/esp8266/core_esp8266_wiring.cpp line 188
0x40201f12: loop() at /Users/janik/Documents/Arduino/WordClock/WordClock.ino line 474
0x401005e0: ets_post(uint8, ETSSignal, ETSParam) at /Users/janik/Library/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/cores/esp8266/core_esp8266_main.cpp line 177
0x4020d384: loop_wrapper() at /Users/janik/Library/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/cores/esp8266/core_esp8266_main.cpp line 197

And this the encoded from the ESPSaveCrash library:

Crash # 1 at 1814320 ms
Restart reason: 2
Exception cause: 9
epc1=0x402059f9 epc2=0x00000000 epc3=0x00000000 excvaddr=0x3ffee9ff depc=0x00000000
>>>stack>>>
3fffff00: 4023bb8a 3ffee95c 4010095a 4a7ef9db 
3fffff10: 3fffdad0 00000000 3ffee8f4 40205a45 
3fffff20: 3fffdad0 3ffee8f4 3ffee8f4 40205ae7 
3fffff30: 00000000 4bc6a7f0 3ffeec08 4020113e 
3fffff40: 00000000 00000000 4bc6a7f0 00000000 
3fffff50: 001bab7b 00000001 4010095a 389374bc 
3fffff60: 00000000 00000000 3ffee760 3ffeed50 
3fffff70: 3fffdad0 00000000 3ffee95c 40201f12 
3fffff80: 00000000 00000000 00000001 401005e0 
3fffff90: 3fffdad0 00000000 3ffeed10 3ffeed50 
3fffffa0: 3fffdad0 00000000 3ffeed10 4020d384 
3fffffb0: feefeffe feefeffe 3ffe8510 401013e5 
<<<stack<<<

And this is my code (I know kinda messy but I've tried to comment as much as possible) / you can ignore the whole setting Leds part, which also has some german comments but that function only sets the leds, so only the letters light up which are needed to display the current time:


#include <FastLED.h>
#include <RTClib.h>
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ButtonKing.h>
#include <EspSaveCrash.h>

#define NUM_LEDS 110
#define DATA_PIN 5

EspSaveCrash SaveCrash;
char *_debugOutputBuffer;
#define DEBUG_OUTPUT_SIZE 2048

const char* ssid = "myssid"; 
const char* password = "mypassword";
long utcOffsetInSeconds = 7200;
int refreshtime;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, utcOffsetInSeconds);
CRGB leds[NUM_LEDS];
CHSV color = CHSV(0, 255, 150);
long lastcolor = 0;
long currcolor;
RTC_DS3231 rtc;
ButtonKing button(13, false);
int lastminute;
boolean forcetimeupdate;
int timeout, hour1, minute1, second1;
float brightness, brg, brg1;
boolean nexthour;
boolean einstrue;
int hourled;
boolean active = true;
boolean diffcolor = false;

//update time function
void updatetime() {
  if ((WiFi.status() == WL_CONNECTED)) {
    timeClient.update(); //CRASHES HERE FOR SOME REASON WITH EXCEPTION 9
    delay(100);
    Serial.println("update");
    //check if time from server is legit, otherwise get time again from NTP
    while (timeClient.getEpochTime() < 1601573968) {
      timeClient.update();
      ArduinoOTA.handle();
      leds[10] = CRGB::Orange;
      leds[0] = CRGB::Orange;
      leds[109] = CRGB::Orange;
      leds[99] = CRGB::Orange;
      FastLED.show();
      delay(500);
      fill_solid(leds, NUM_LEDS, CRGB::Black);
      FastLED.show();
      delay(100);
    }
    rtc.adjust(DateTime(2019, 1, 21, timeClient.getHours(), timeClient.getMinutes(), timeClient.getSeconds()));
    refreshtime = millis();
    forcetimeupdate = false;
  }
  else {
    //no connection to wifi, trying to reconnect to wifi
    WiFi.disconnect();
    Serial.println("trying to reconnect to WiFi");
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    int timeout1 = 0;
    while (WiFi.status() != WL_CONNECTED && timeout1 < 25) {
      timeout1 = timeout1 + 1;
      delay(1000);
      Serial.print(".");

    }
    if (!(timeout1 < 25)) {
      Serial.println("connection could not be established: Timeout");
      //setting forcetimeupdate to true, so it will be called every minute till success
      forcetimeupdate = true;
      refreshtime = millis();
    }
    else {
      Serial.println("connected");
      forcetimeupdate = false;
      updatetime();
    }
  }
}

//timeClient.begin() always call early in setup() otherwise exception
void setup() {
  _debugOutputBuffer = (char *) calloc(DEBUG_OUTPUT_SIZE, sizeof(char));
  button.setClick(onClick);
  button.setLongClickStop(onLongPress);
  button.setDoubleClick(onDoubleClick);
  Serial.begin(9600);

  while (!Serial) {
    delay(100);
  }
  SaveCrash.print();
  pinMode(13, INPUT);
  pinMode(A0, INPUT);
  delay(100);
  Serial.println("starting");
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  //FastLED.setMaxPowerInVoltsAndMilliamps(5,500);


  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  timeout = 0;
  while (WiFi.status() != WL_CONNECTED && timeout < 25) {
    timeout = timeout + 1;
    delay(1000);
    Serial.print(".");

  }
  if (!(timeout < 25)) {
    Serial.println("connection could not be established: Timeout");
    forcetimeupdate = true;
    refreshtime = millis();
  }
  else {
    Serial.println("connected");
    forcetimeupdate = false;
  }


  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  ArduinoOTA.setHostname("WordClock");
  ArduinoOTA.begin();
  delay(2000);
  timeClient.begin();
  updatetime();
  //rtc.adjust(DateTime(2019, 1, 21, 12, 35, 40));
  //setting inital brightness of the leds
  brightness = analogRead(A0);
  brg1 = map(brightness, 0, 1024, 0, 255);
  //configuring the inital time
  lastminute = -3;
  DateTime now = rtc.now();
  hour1 = now.hour();
  minute1 = now.minute();
  second1 = now.second();
  //startup animation
  for (int i = 0; i < 11; i++) { //direction down
    for (int j = 0; j < 11; j++) { //fill line
      leds[j + 10 * i] = CRGB::White;
    }
    if (!((i - 2) < 0)) {
      for (int k = 0; k < 11; k++) {
        leds[k + 10 * (i - 2)] = CRGB::Black;
      }
    }
    FastLED.show();
    delay(70);
    Serial.println("-");
  }
}

//basic leds needed for every displayed time
void setbasic() {
  //es ist / it is
  for (int i = 0; i < 6; i++) {
    if (!(i == 2)) {
      leds[i] = color;
    }
  }
  FastLED.show();
}


//setting leds according to current time
void setleds(int hour2, int minute2) {
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  //12 hour format
  if (hour2 > 12) {
    hour2 = hour2 - 12;
  }
  else if (hour2 == 0) {
    hour2 = 12;
  }
  einstrue = false;
  if (minute2 < 4) {
    nexthour = false;
    einstrue = true;
    //uhr
    for (int i = 99; i < 102; i++) {
      leds[i] = color;
    }
  }
  else if (minute2 < 8 && minute2 > 3) {
    //fünf
    leds[7] = color;
    leds[8] = color;
    leds[9] = color;
    leds[10] = color;
    //nach
    leds[38] = color;
    leds[39] = color;
    leds[40] = color;
    leds[41] = color;
    nexthour = false;

  }
  else if (minute2 < 13 && minute2 > 7) {
    //zehn
    leds[18] = color;
    leds[19] = color;
    leds[20] = color;
    leds[21] = color;

    //nach
    leds[38] = color;
    leds[39] = color;
    leds[40] = color;
    leds[41] = color;
    nexthour = false;
  }
  else if (minute2 < 18 && minute2 > 12) {
    //viertel
    leds[26] = color;
    leds[27] = color;
    leds[28] = color;
    leds[29] = color;
    leds[30] = color;
    leds[31] = color;
    leds[32] = color;
    //nach
    leds[38] = color;
    leds[39] = color;
    leds[40] = color;
    leds[41] = color;
    nexthour = false;
  }
  else if (minute2 < 23 && minute2 > 17) {
    //zwanzig
    leds[11] = color;
    leds[12] = color;
    leds[13] = color;
    leds[14] = color;
    leds[15] = color;
    leds[16] = color;
    leds[17] = color;
    //nach
    leds[38] = color;
    leds[39] = color;
    leds[40] = color;
    leds[41] = color;
    nexthour = false;

  }
  else if (minute2 < 28 && minute2 > 22) {
    //fünf
    leds[7] = color;
    leds[8] = color;
    leds[9] = color;
    leds[10] = color;
    //vor
    leds[35] = color;
    leds[36] = color;
    leds[37] = color;
    //halb
    leds[44] = color;
    leds[45] = color;
    leds[46] = color;
    leds[47] = color;
    nexthour = true;
  }
  else if (minute2 < 33 && minute2 > 27) {
    //halb
    leds[44] = color;
    leds[45] = color;
    leds[46] = color;
    leds[47] = color;
    nexthour = true;
  }
  else if (minute2 < 38 && minute2 > 32) {
    //fünf
    leds[7] = color;
    leds[8] = color;
    leds[9] = color;
    leds[10] = color;
    //nach
    leds[38] = color;
    leds[39] = color;
    leds[40] = color;
    leds[41] = color;
    //halb
    leds[44] = color;
    leds[45] = color;
    leds[46] = color;
    leds[47] = color;
    nexthour = true;

  }
  else if (minute2 < 43 && minute2 > 37) {
    //zwanzig
    leds[11] = color;
    leds[12] = color;
    leds[13] = color;
    leds[14] = color;
    leds[15] = color;
    leds[16] = color;
    leds[17] = color;
    //vor
    leds[35] = color;
    leds[36] = color;
    leds[37] = color;
    nexthour = true;
  }
  else if (minute2 < 48 && minute2 > 42) {
    //viertel
    leds[26] = color;
    leds[27] = color;
    leds[28] = color;
    leds[29] = color;
    leds[30] = color;
    leds[31] = color;
    leds[32] = color;
    //vor
    leds[35] = color;
    leds[36] = color;
    leds[37] = color;
    nexthour = true;
  }
  else if (minute2 < 53 && minute2 > 47) {
    //zehn
    leds[18] = color;
    leds[19] = color;
    leds[20] = color;
    leds[21] = color;
    //vor
    leds[35] = color;
    leds[36] = color;
    leds[37] = color;
    nexthour = true;
  }
  else if (minute2 < 58 && minute2 > 52) {
    //fünf
    leds[7] = color;
    leds[8] = color;
    leds[9] = color;
    leds[10] = color;
    //vor
    leds[35] = color;
    leds[36] = color;
    leds[37] = color;
    nexthour = true;
  }
  else if (minute2 > 57) {
    nexthour = true;
    einstrue = true;
    //uhr
    for (int i = 99; i < 102; i++) {
      leds[i] = color;
    }
  }

  if (nexthour == true) {
    hourled = hour2 + 1;
    if (hourled == 13) {
      hourled = 1;
    }
  } else {
    hourled = hour2;
  }

  switch (hourled) {
    case 1:

      if (!einstrue) {
        leds[60] = color;
      }
      leds[61] = color;
      leds[62] = color;
      leds[63] = color;
      break;
    case 2:

      leds[62] = color;
      leds[63] = color;
      leds[64] = color;
      leds[65] = color;
      break;
    case 3:
      leds[67] = color;
      leds[68] = color;
      leds[69] = color;
      leds[70] = color;
      break;
    case 4:

      leds[77] = color;
      leds[78] = color;
      leds[79] = color;
      leds[80] = color;
      break;
    case 5:

      leds[73] = color;
      leds[74] = color;
      leds[75] = color;
      leds[76] = color;
      break;
    case 6:
      leds[104] = color;
      leds[105] = color;
      leds[106] = color;
      leds[107] = color;
      leds[108] = color;
      break;
    case 7:

      leds[55] = color;
      leds[56] = color;
      leds[57] = color;
      leds[58] = color;
      leds[59] = color;
      leds[60] = color;
      break;
    case 8:

      leds[89] = color;
      leds[90] = color;
      leds[91] = color;
      leds[92] = color;
      break;
    case 9:

      leds[81] = color;
      leds[82] = color;
      leds[83] = color;
      leds[84] = color;
      break;
    case 10:

      leds[93] = color;
      leds[94] = color;
      leds[95] = color;
      leds[96] = color;
      break;
    case 11:

      leds[85] = color;
      leds[86] = color;
      leds[87] = color;
      break;
    case 12:
      leds[49] = color;
      leds[50] = color;
      leds[51] = color;
      leds[52] = color;
      leds[53] = color;
      break;

  }
  setbasic();

}

void loop() {
  button.isClick();
  ArduinoOTA.handle();
  //forcetimeupdate is true when last updatetime() wasnt successful because of no internet connection
  if (forcetimeupdate) {
    //update from NTP every minute
    if ((millis() - refreshtime) > 60000) {
      updatetime();
    }
  //normally sync time from NTP every 30min
  } else {
    //update from NTP every 30min
    if ((millis() - refreshtime) > 1800000) {
      updatetime();
    }

  }

  if (active) {
    //get current time
    DateTime now = rtc.now();
    hour1 = now.hour();
    minute1 = now.minute();
    second1 = now.second();
    /*Serial.print(hour1);
    Serial.print(":");
    Serial.print(minute1);
    Serial.print(":");
    Serial.println(second1);*/
    //make colors a little bit brighter than normal white
    if (diffcolor) {
      if ((brg1 + 30) >= 255) {
        color = CHSV(minute1 * 4.25, 255, 255);
      }
      else {
        color = CHSV(minute1 * 4.25, 255, brg1 + 30);
      }
    }
    else {
      color = CHSV(0, 0, brg1);
    }

    //fill_solid(leds,NUM_LEDS,CRGB::Black);
    //only update when time has changed
    if (!(lastminute == minute1)) {
      setleds(hour1, minute1);
    }
    lastminute = minute1;

    //update brightness to match surrounding, only update brightness if brightness changed 20 to last change
    brightness = analogRead(A0);
    brg = map(brightness, 0, 1024, 30, 255); //30 , 1024, 0, 255
    if ((brg1 - brg) > 20 || (brg - brg1) > 20) {
      if (brg <= 30) {
        // FastLED.setBrightness(10);
        brg1 = 30;
      }
      else if (brg >= 255) {
        //FastLED.setBrightness(255);
        brg1 = 255;
      }
      else {
        // FastLED.setBrightness(brg);
        brg1 = brg;
      }
       //again make colors a little bit brighter than normal white
      if (diffcolor) {
       
        if ((brg1 + 30) >= 255) {
          color = CHSV(minute1 * 4.25, 255, 255);
        }
        else {
          color = CHSV(minute1 * 4.25, 255, brg1 + 30);
        }
      }
      else {
        color = CHSV(0, 0, brg1);
      }
      setleds(hour1, minute1);
      brg1 = brg;
      Serial.print("brightness: ");
      Serial.print(brg1);
      Serial.print(" absolut brg: ");
      Serial.println(brightness);
    }
  }
  ArduinoOTA.handle();
  delay(50);
}



//Buttonking functions for changing UTC offset
void onLongPress() {
  if (utcOffsetInSeconds == 7200) {
    Serial.println("Changing UTC Offset to 3600");
    utcOffsetInSeconds = 3600;
  }
  else if (utcOffsetInSeconds = 3600) {
    Serial.println("Changing UTC Offset to 7200");
    utcOffsetInSeconds = 7200;
  }
  timeClient.setTimeOffset(utcOffsetInSeconds);
  updatetime();
  if (active) {
    lastminute = 300;
    setleds(hour1, minute1);
  }
}

//Buttonking functions for checking and displaying wifi connectivity and change between white and dynamic color (color changing to current time, mapped HSV to minutes)
void onDoubleClick() {
  if ((WiFi.status() == WL_CONNECTED)) {
    Serial.println("Wifi connected");
    for (int i = 0; i < 11; i++) { //direction down
      for (int j = 0; j < 11; j++) { //fill line
        leds[j + 10 * i] = CRGB::Green;
      }
      if (!((i - 2) < 0)) {
        for (int k = 0; k < 11; k++) {
          leds[k + 10 * (i - 2)] = CRGB::Black;
        }
      }

      FastLED.show();
      delay(50);
    }

  }
  else if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wifi not connected");
    for (int i = 0; i < 11; i++) { //direction down
      for (int j = 0; j < 11; j++) { //fill line
        leds[j + 10 * i] = CRGB::Red;
      }
      if (!((i - 2) < 0)) {
        for (int k = 0; k < 11; k++) {
          leds[k + 10 * (i - 2)] = CRGB::Black;
        }
      }
      FastLED.show();
      delay(70);
    }
  }
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  FastLED.show();
  if (diffcolor) {
    diffcolor = false;
  } else {
    diffcolor = true;
  }
  if (active) {
    lastminute = 300;
    setleds(hour1, minute1);
  }

}

//Buttonking functions for changing active status: toggle LEDs on or off
void onClick() {
  Serial.println("Clicked");
  if (active) {
    active = false;
    Serial.println("turning LEDs off");
    fill_solid(leds, NUM_LEDS, CRGB::Black);
    FastLED.show();
  }
  else {
    active = true;
    lastminute = 300;
    Serial.println("turning LEDs on");
  }
}

I'm not sure if the error is on my end or if it is an error in the NTP library. From the error message from the ESPSaveCrash library I know that it's always happening at about 30min, so it's the first time sync. If anyone knows a better more reliable library for an ESP8266 please let me know. I've got the exception on an NodeMCU V3 and a Wemos D1 Mini.

c++
datetime
arduino
esp8266
ntp
asked on Stack Overflow May 4, 2021 by Janik • edited May 4, 2021 by Janik

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0