Arduino or ESP32 Reboots because of Oled Menu

Hello together , I am working on a Oled Menu using the Adafruit_SSD1306.h and OneButton library. The idea is to navigating and changing values true the Menu using only 3 buttons. Each button as several function like normal Click, double Click, long Click etc. With the One Click Select Button i can navigate true the Menu forward. With the Double Click Select Button i go to a Variable Pages where i can change several values with the Plus and Minus Button. To go back from the Variable Pages to the Menu Pages again using the Double Click Select Button. All this what i have explained until now is working. The problem that i have is the folowing. When i am in the last Page of the Main Menu, pressing the Minus Button it brings me to a Sub Menu. Here i have also three pages where i can navigate forward with the One Click Select Button. Reaching the last Page of the Sub Menu clicking again on Minus Button it would bring me back to the Main Menu. Exactly on this last step my Microcontroller Reboots by himself all the time.

I am using a variable byte PageSwitch = 0; to controll where i am inside the Menu. For sure at some point inside the code i am not using this variable correctly and this brings the Microcontroller to Reboot.

Follows my Code

#include <EEPROM.h>
#include <OneButton.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 
#define SCREEN_HEIGHT 64 
#define display_RESET -1

const char*Vartext[] {"Text_0", "Text_1", "Text_2",
  "Text_3", "Text_4"
};

const byte maxAnz = sizeof(Vartext) / sizeof(Vartext[0]);

const int mindata[maxAnz] {0, 0, 0, 0, 0}; 
const int maxdata[maxAnz] {10000, 200, 300, 500, 1000};
uint32_t longstart;
byte Varindex;
byte Page = 0;
byte Page2 = 0;
byte PageSwitch = 0;
bool input;     
bool changed;     
bool changed2;     
bool datachanged ;


struct mydaten {
  int VarData[maxAnz];
} daten;


const byte pinsel = 2;    // Select Button
const byte pinplus = 4;   // Plus Button
const byte pinminus = 5;  // Minus Button

// Instanzen
OneButton Btnsel(pinsel, true);
OneButton Btnplus(pinplus, true);
OneButton Btnminus(pinminus, true);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, display_RESET);

void setup() {
  Serial.begin(115200);

  EEPROM.get(0, daten);
  for (byte i = 0; i < maxAnz; i++) {
    checkminmax();
  }
  changed = true;
  changed2 = true;
  Btnsel.attachClick(selClick);
  Btnsel.attachDoubleClick(selDblClick);
  Btnplus.attachClick(plusClick);
  Btnplus.attachDuringLongPress(plusDurPress);
  Btnplus.attachLongPressStart(LongStart);
  Btnminus.attachClick(minusClick);
  Btnminus.attachDuringLongPress(minusDurPress);
  Btnminus.attachLongPressStart(LongStart);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextWrap(false);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(20, 30); display.print(F("Menu"));
  display.setTextSize(2);
  display.display();
  delay(2000);

PageSwitch = 1;
}

void loop() {
  Btnsel.tick();
  Btnplus.tick();
  Btnminus.tick();

  if (input)Showinput();
  else if (PageSwitch == 1) {
    Show(Page);
  }
  else if (PageSwitch == 2) {
    Show2(Page2);
  }
}


void selClick() {
  changed = true;
  changed2 = true;
  if (input) {  
    Varindex++;
    if (Varindex >= maxAnz) Varindex = 0;
  }
  if (Show && PageSwitch == 1) {
    Page++;
    if (Page >= 4) Page = 0;
  }

  if (Show2 && PageSwitch == 2) {
    Page2++;
    if (Page2 >= 4) Page2 = 0;
  }
}
void selDblClick() {
  if (input) saveEEprom(); 
  input = !input; 
  changed = true;
  changed2 = true;
#ifdef debug
  for (byte i = 0; i < maxAnz; i++) {
    Serial.print(Vartext[i]); Serial.print('\t');
    Serial.println(daten.VarData[i]);
  }
  Serial.print("Change visual mode"); Serial.println(input);
  Serial.print("Index "); Serial.println(Varindex);
#endif
}

void plusClick() {
  click(1);
}
void minusClick() {
  click(-1);
}
void plusDurPress() {
  longclick(1);
}
void minusDurPress() {
  longclick(-1);
}
void LongStart() {
  longstart = millis();
}
void click(int inc) {
  if (input) {
    changed = true;
    changed2 = true;
    datachanged = true;
    daten.VarData[Varindex] += inc;
    checkminmax();
  }
}
void longclick(int direction) {
  static uint32_t oldtime;
  int inc = 10;
  if (millis() - longstart > 5000) inc = 100;
  if (millis() - oldtime >= 100 && input) {
    oldtime = millis();
    changed = true;
    changed2 = true;
    datachanged = true;
    daten.VarData[Varindex] += inc * direction;
    checkminmax();
  }
}

void checkminmax() {
  if (daten.VarData[Varindex] < mindata[Varindex]) {
    daten.VarData[Varindex] = mindata[Varindex];
  }
  if (daten.VarData[Varindex] > maxdata[Varindex]) {
    daten.VarData[Varindex] = maxdata[Varindex];
  }
}

void Showinput() { 
  if (changed || changed2) {
    changed = false;
    changed2 = false;
    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(0, 0); display.print("input");
    display.setCursor(0, 20); display.print(Vartext[Varindex]);
    display.setCursor(10, 40); display.print(daten.VarData[Varindex]);
    display.display();
  }
}

void Show(byte Page) { 
  if (changed) { 
    changed = false;
    display.clearDisplay();
    if (Page == 0) {
      display.setTextSize(2);
      display.setCursor(0, 0);
      display.print("Main Menu");
    }
    else if (Page == 1) { 
      display.setTextSize(2);
      display.setCursor(0, 0); display.print("Page 1");
    }
    else if (Page == 2) {
      display.setTextSize(2);
      display.setCursor(0, 0); display.print("Page 2");
    }
    else if (Page == 3) { 
      changed = true;
      display.setTextSize(1);
      display.setCursor(0, 0); display.print("Go to SubMenu");
      display.setTextSize(1);
      display.setCursor(20, 20); display.print("Press Down Button");
      if (!digitalRead(pinminus) ) {
        PageSwitch = 2;
        Show2(Page2);
        changed = true;
      }
    }
    display.display();
  }
}

void Show2(byte Page2) { 
  if (changed2) { 
    changed2 = false;
    display.clearDisplay();
    if (Page2 == 0) { 
      display.setTextSize(2);
      display.setCursor(0, 0);
      display.print("Sub Menu");
    }
    else if (Page2 == 1) { 
      display.setTextSize(2);
      display.setCursor(0, 0); display.print("Sub Page 1");
    }
    else if (Page2 == 2) { 
      display.setTextSize(2);
      display.setCursor(0, 0); display.print("Sub Page 2");
    }
    else if (Page2 == 3) { 
      changed2 = true;
      display.setTextSize(1);
      display.setCursor(0, 0); display.print("Go to Main Menu");
      display.setTextSize(1);
      display.setCursor(20, 20); display.print("Press Down Button");
      if (!digitalRead(pinminus) ) {
        changed2 = true;
        PageSwitch = 1;
        Show(Page);
      }
    }
    display.display();
  }
}

void saveEEprom() {
  if (datachanged) {
    datachanged = false;
#ifdef debug
    Serial.println("Save in EEprom");
#endif
    EEPROM.put(0, daten);
  }
}

ESP's Loop function must run because of WiFi handling. if it blocked by some thing longer as 8 seconds then chip resets by watchdog.

Thanks for the reply. I am not using Wi-Fi and the esp32 only reboots exactly at the moment when I press the Minus Button inside the Submenu when I want to go back to the Mainmenu

Use the Arduino command yield() or delay(0) liberty whenever you are stalling the Arduino code. This allows the Arduino dedicated core_1 to give freeRTOS time to service the RF/housekeeping core_0.

Still, you cannot stall core_1 as core_0 starves. More than just RF happens on core_0.

A better practice is to make static strings take this form:

 Serial.println(F("Save in EEprom"));

I understand what you are saying but I don't see how or where in the code I am stalling the core 1 and the core 0 would starve. If I use the code without the Submenu functionality the esp32 doesn't reboot.

Post the ESP32 Exception Decoder results.

I did not mean to indicate that a stalled core_0 was your specific problem at hand; rather it is always a concern and I was explaining why.

Your specific issue may be caused by a fouled pointer or even a misplaced call.

To me, this is not how I would have written the routine.

      if (!digitalRead(pinminus) ) {
        changed2 = true;
        PageSwitch = 1;
        Show(Page);  // <-- why not return a state #
      }
    }
    display.display();  // <-- and use state # in a switch-case?
  }
}

My personal belief is you need to get the display refresh/updates out of the menu-submenu functions and isolate these into one (1) display routine.

switch...case - Arduino Reference

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.