esp8266 display library crashing display.dispaly()

trying to convert my programs over for a mesh network but ive stumbled across a problem. It seems everything works fine if comment out display.display(); from my loop. otherwise the program crashes on startup? any advice?

#include "painlessMesh.h"
// WiFi Credentials
#define   MESH_PREFIX     "MNW"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555
#include <EEPROM.h>
#include <SoftwareSerial.h>

#include <Adafruit_SSD1306.h>
#define OLED_RESET LED_BUILTIN
Adafruit_SSD1306 display(OLED_RESET);

#include <FS.h>   //Include File System Headers

Scheduler userScheduler;
painlessMesh  mesh;
void sendMessage() ;
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );



int addr = 0;
unsigned long now = 0;

bool uartReady = 0;
bool pwmReady = 1;
bool calibrate = 0;
unsigned long CO2 = 0;
int calibration = 200; //subtract from co2 ppm reading
//int pwmPIN = 13;

void ICACHE_RAM_ATTR PwmPinISR();
void ICACHE_RAM_ATTR getPwmReading();
volatile unsigned long pwmPulseDuration;
volatile boolean pwmPulseCaptured = false;
volatile boolean errorFlag = false;
const byte pwmPin = 13;//connect pwm input to D7 GPIO 13

unsigned long th, tl, pwmPPM = 0;
unsigned long now2 = 0;
unsigned long now3 = 0;
unsigned long pwmMIN = 50000;
unsigned long pwmMAX = -10;
unsigned long ch = 0;
SoftwareSerial mySerial(12, 14); // RX, TX
unsigned char hexdata[10] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; //Read the gas density command /Don't change the order
unsigned char hexcal[10] = {0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78};

struct {
  unsigned long pwmc02ppm = 0;
  unsigned long uartc02ppm = 0;
  unsigned long SecondsOn = 0;
} _packet;

void sendMessage() {
  DynamicJsonDocument doc(2024);
  doc["ID"] = "C02NODE1";
  doc["pwmc02ppm"] = _packet.pwmc02ppm;
  doc["uartc02ppm"] = _packet.uartc02ppm;
  doc["SecondsOn"] = _packet.SecondsOn;
  String msg ;
  serializeJson(doc, msg);
  mesh.sendBroadcast( msg );
  Serial.println(msg);
  taskSendMessage.setInterval((TASK_SECOND * 1));
}
void newConnectionCallback(uint32_t nodeId) {
  Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}
void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}
void nodeTimeAdjustedCallback(int32_t offset) {
  Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}
void PwmPinISR()
{
  if (pwmPulseCaptured == false)//ok to read new pulse
  {
    static unsigned long startTime;
    if (digitalRead(pwmPin)) // Gone HIGH
      startTime = micros();
    else  // Gone LOW
    {
      pwmPulseDuration = micros() - startTime;
      pwmPulseCaptured = true;
      if (pwmPulseDuration > 1100000ul)//greater than max time 1004 ms
        errorFlag = true;
    }
  }
}
void getPwmReading()
{
  static unsigned long th, tl = 0;
  if (errorFlag)
  {
    Serial.println("PWM read error");
    errorFlag = false;
  }
  else
  {
    th = pwmPulseDuration / 1000;
    Serial.print("pwm pulse length high ms = ");
    Serial.println(th);
    tl = 1004 - th;
    pwmPPM = 50000UL * (th - 2) / (th + tl - 4);
    Serial.print("PWM PPM=");
    Serial.println(pwmPPM);
    _packet.pwmc02ppm = pwmPPM;
  }
  pwmPulseCaptured = false;//reset for next capture

}
void receivedCallback( uint32_t from, String &msg ) {
  String json;
  DynamicJsonDocument doc(1024);
  json = msg.c_str();
  DeserializationError error = deserializeJson(doc, json);
  if (error)
  {
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.c_str());
  }
}
void setup() {
  Serial.begin(115200);
  SPIFFS.begin();
  Serial.println("IP address: ");
  // Serial.println(WiFi.localIP());
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  pinMode(12, INPUT);
  attachInterrupt(digitalPinToInterrupt(pwmPin), PwmPinISR, CHANGE);
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages
  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
  userScheduler.addTask( taskSendMessage );
  taskSendMessage.enable();
  Serial.println("booted");
  while (!Serial) {}
  mySerial.begin(9600);
}


void loop() {

  if ( millis() - now >= 1000) {
    _packet.SecondsOn++;
    now = millis();
    mySerial.write(hexdata, 9);
    // delay(500);
    for (int i = 0, j = 0; i < 9; i++) {
      if (mySerial.available() > 0) {
        long hi, lo;
        ch = mySerial.read();
        if (i == 2) {
          hi = ch;    //High concentration
        }
        if (i == 3) {
          lo = ch;    //Low concentration
        }
        if (i == 8) {
          CO2 = hi * 256 + lo; //CO2 concentration
          Serial.print("UART PPM=");
          Serial.println(CO2);
          _packet.uartc02ppm = CO2;

        }
      }
    }

    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("UART-PPM=");
    display.println(CO2);
    display.print("PWM-PPM=");
    display.println(pwmPPM);
    display.print("Time=");
    display.println(_packet.SecondsOn);
    display.display(); ///comment this and program works
  }
  if (millis() - now3 >= 2000) {

    now3 = millis();
    if (pwmPulseCaptured)//this could be put on a periodic timer
    {
      getPwmReading();
    }
  }
  mesh.update();
}

Here is a decoded stack trace. what is it trying to say?

Decoding stack results
0x4020f184: Twi::write_bit(bool) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_si2c.cpp line 282
0x4020f248: Twi::write_byte(unsigned char) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_si2c.cpp line 304
0x4020f302: Twi::writeTo(unsigned char, unsigned char*, unsigned int, unsigned char) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_si2c.cpp line 338
0x4020f4b4: twi_writeTo(unsigned char, unsigned char*, unsigned int, unsigned char) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_si2c.cpp line 984
0x4020f4b4: twi_writeTo(unsigned char, unsigned char*, unsigned int, unsigned char) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_si2c.cpp line 984
0x4020c828: TwoWire::endTransmission(unsigned char) at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\Wire\Wire.cpp line 171
0x4020c850: TwoWire::endTransmission() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\Wire\Wire.cpp line 180
0x4020c524: Adafruit_SSD1306::display() at C:\Users\Laptop\Documents\Arduino\libraries\Adafruit_SSD1306\Adafruit_SSD1306.cpp line 914
0x4020db38: Print::println() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\Print.cpp line 186
0x40206bec: loop() at C:\Users\Laptop\Documents\Arduino\C02_MESH_NETWORK/C02_MESH_NETWORK.ino line 187
0x4020eaa0: loop_wrapper() at C:\Users\Laptop\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 197

Sometimes it does work. when i moved

    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);

to the end of setup then there is a 50% chance that the program runs??

it boots and draws the screen the first time then stops drawing the screen.

What's the exception/error message/error code you're getting? How much memory are you using? (ESP.getFreeHeap()).
Your code is too complex, debug one thing at a time. Get the display working without all the mesh and PWM stuff.

Pieter

PieterP:
What's the exception/error message/error code you're getting? How much memory are you using? (ESP.getFreeHeap()).
Your code is too complex, debug one thing at a time. Get the display working without all the mesh and PWM stuff.

Pieter

the display does work without the mesh network. i have been using the code with WiFi library for some time.

as far as resource usage maybe this can help,

"C:\\Users\\Laptop\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\xtensa-lx106-elf-gcc\\2.5.0-4-b40a506/bin/xtensa-lx106-elf-size" -A "c:\\ArduinoTemp/C02_MESH_NETWORK.ino.elf"
Sketch uses 366388 bytes (35%) of program storage space. Maximum is 1044464 bytes.
Global variables use 34408 bytes (42%) of dynamic memory, leaving 47512 bytes for local variables. Maximum is 81920 bytes.

notsolowki:
the display does work without the mesh network. i have been using the code with WiFi library for some time.

In that case, start from the display only code, and add a minimal amount of WiFi or Mesh code to get the error to trigger. Is it caused by adding WiFi? By adding the Mesh library? By your PWM interrupts messing up the I²C timing?

Isolate the problem and post a minimal working example that demonstrates the error.

notsolowki:
as far as resource usage maybe this can help,

"C:\\Users\\Laptop\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\xtensa-lx106-elf-gcc\\2.5.0-4-b40a506/bin/xtensa-lx106-elf-size" -A "c:\\ArduinoTemp/C02_MESH_NETWORK.ino.elf"

Sketch uses 366388 bytes (35%) of program storage space. Maximum is 1044464 bytes.
Global variables use 34408 bytes (42%) of dynamic memory, leaving 47512 bytes for local variables. Maximum is 81920 bytes.

That only tells you about the static memory usage. Many ESP8266 libraries allocate dynamic memory. You have to print the memory usage at runtime. See the ESP.getFreeHeap function I linked to earlier. Also print the fragmentation. Libraries — ESP8266 Arduino Core 3.1.2-21-ga348833 documentation

When you get an error message, please post the entire output in the serial monitor, as well as the decoded stack trace/exceptions.

PieterP:
In that case, start from the display only code, and add a minimal amount of WiFi or Mesh code to get the error to trigger. Is it caused by adding WiFi? By adding the Mesh library? By your PWM interrupts messing up the I²C timing?

Isolate the problem and post a minimal working example that demonstrates the error.
That only tells you about the static memory usage. Many ESP8266 libraries allocate dynamic memory. You have to print the memory usage at runtime. See the ESP.getFreeHeap function I linked to earlier. Also print the fragmentation. Libraries — ESP8266 Arduino Core 3.1.2-21-ga348833 documentation

When you get an error message, please post the entire output in the serial monitor, as well as the decoded stack trace/exceptions.

First and foremost maybe you can help me understand what a mesh network is. I have been trying to get advice about how to handle this project here but no body has chimed in.

my project consists of about 25 nodes. i was initially hoping to get them all to connect to an esp soft_Ap but as i found this is very limited because the esp's are too weak to handle the processing and ram. so i have now come across something called mesh network for esp8266. i have no idea how it really works or if it even will work.

i want to receive data from these nodes about 1 time a second. basically have a master node that collects all the data from all the other nodes and sends it to a web server. can this mesh network handle 25 nodes? is there another way except for NRF24 to handle the communication?

As i was saying earlier i have no idea what to expect. im having trouble getting more than 2 nodes communicating with eachother

At minimum here is a mesh network i have put together with 2 node. im my eyes im using master receiver as naming because the receiver is the important node to parse data and handle webserver. this is receiver without webserver,

receiver,

#include "painlessMesh.h"
#define   MESH_PREFIX     "MNW"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler userScheduler;
painlessMesh  mesh;
void sendMessage() ;
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
  //  DynamicJsonDocument doc(2024);
  //  doc["ID"] = "NODE1";
  //  String msg ;
  //  serializeJson(doc, msg);
  //  mesh.sendBroadcast( msg );
  //  Serial.println(msg);
  //  taskSendMessage.setInterval((TASK_SECOND * 1));
}
void newConnectionCallback(uint32_t nodeId) {
  Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}
void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}
void nodeTimeAdjustedCallback(int32_t offset) {
  Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}
void receivedCallback( uint32_t from, String &msg ) { // heres where teh message are handled
  String json;
  DynamicJsonDocument doc(1024);
  json = msg.c_str();
  DeserializationError error = deserializeJson(doc, json);
  if (error)
  {
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.c_str());
  }
  if (strcmp(doc["ID"], "NODE1") == 0) { //if id field of json object is node1
    Serial.println("NODE1");
  }
  if (strcmp(doc["ID"], "NODE1") == 0) { //if id field of json object is node2
    Serial.println("NODE1");
  }
}
void setup() {
  Serial.begin(115200);
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages
  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
  userScheduler.addTask( taskSendMessage );
  taskSendMessage.enable();
}

void loop() {
  mesh.update();
}

client node,

#include "painlessMesh.h"
#define   MESH_PREFIX     "MNW"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler userScheduler;
painlessMesh  mesh;
void sendMessage() ;
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
    DynamicJsonDocument doc(2024);
    doc["ID"] = "NODE1";
    String msg ;
    serializeJson(doc, msg);
    mesh.sendBroadcast( msg );
    Serial.println(msg);
    taskSendMessage.setInterval((TASK_SECOND * 1));
}
void newConnectionCallback(uint32_t nodeId) {
  Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}
void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}
void nodeTimeAdjustedCallback(int32_t offset) {
  Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}
void receivedCallback( uint32_t from, String &msg ) { // heres where teh message are handled
//  String json;
//  DynamicJsonDocument doc(1024);
//  json = msg.c_str();
//  DeserializationError error = deserializeJson(doc, json);
//  if (error)
//  {
//    Serial.print("deserializeJson() failed: ");
//    Serial.println(error.c_str());
//  }
//  if (strcmp(doc["ID"], "NODE1") == 0) { //if id field of json object is node1
//    Serial.println("NODE1");
//  }
//  if (strcmp(doc["ID"], "NODE1") == 0) { //if id field of json object is node2
//    Serial.println("NODE1");
//  }
}
void setup() {
  Serial.begin(115200);
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages
  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
  userScheduler.addTask( taskSendMessage );
  taskSendMessage.enable();
}

void loop() {
  mesh.update();
}

i think master and receiver for mesh network is not proper termanology. but i like to think master node because it will be the one parsing the collected data from other nodes.

The callback function "receivedCallback" is responsible for handling the incoming JSON object or String etc.

the calback function "sendMessage" is responsible for writing message to the mesh network

By default these messages are on a timer. i left it that way seems reasonable enough. I'm not exactly sure how mesh works. Can i write this code to 20 other nodes with different "doc.[ID]" identifiers and send messages from the each 1 time a second and expect this to work? Do all nodes stay connected? they way i see it. its like a network switch without routing and every packet is broadcasted to every connected device.

A mesh network is a solution to limited transmission distance. If your radio can only reach others a mile away but you need to get a message to one ten miles away you can have intermediate nodes that relay messages.

Typically, such a system isn't put in place just to get data from one end of the line to another but is a network of nodes that help each other by passing messages on towards whichever node is the destination. That is a mesh.

Take a look at XBee kit - they use mesh technology.

A mesh network is a network where devices communicate directly with each other, instead of connecting each device to a central wireless router. The advantage is that this scales much more easily than a centralized design, it adds redundancy, allows greater range, etc.

See ESP-WIFI-MESH | Espressif Systems.

It looks like the Painless Mesh library you're using is a different implementation of the same concept. I've never used that library (or any other mesh libraries) myself, so I can't help you with the specifics.

The point I was trying to make is that it's very hard to debug programs where you have multiple parts that interact like this. You have to isolate the problem. If you can't get mesh communication to work, why throw in a display to make it even more complicated?
Focus on one aspect of your project at once and make sure it fully works (and that you understand how/why it works) before integrating it with the other parts such as displays, SoftwareSerial communication, PWM inputs ...

PieterP:
A mesh network is a network where devices communicate directly with each other, instead of connecting each device to a central wireless router. The advantage is that this scales much more easily than a centralized design, it adds redundancy, allows greater range, etc.

See https://www.espressif.com/en/products/sdks/esp-wifi-mesh/overview.

It looks like the Painless Mesh library you're using is a different implementation of the same concept. I've never used that library (or any other mesh libraries) myself, so I can't help you with the specifics.

The point I was trying to make is that it's very hard to debug programs where you have multiple parts that interact like this. You have to isolate the problem. If you can't get mesh communication to work, why throw in a display to make it even more complicated?
Focus on one aspect of your project at once and make sure it fully works (and that you understand how/why it works) before integrating it with the other parts such as displays, SoftwareSerial communication, PWM inputs ...

i already have a system that has been working fine on wifi until i found out 8 client is maximum for esp8266 in soft_ap mode. i just recently stumbled on mesh networks trying to find a solution. i have about 25 nodes that i need to report to the master. from what i can tell the ESP32 isnt much better. it sounds like the mesh network may not work the way i initially interpreted it. i really need to find a solution to this problem. bluetooth i hear has even less capability. NRF24is pita not sure what else there is.

The esp wifi method was working great until this.

I mean should i open a new thread somewhere else or can i get some advice about methods in this thread

A thread about displays is unlikely to attract mesh networking specialists. If you do start a new thread, post links to your other threads about the same project.

I don't know how to get a mesh network working but am I pointing out the obvious by suggesting that if you want more devices connected to WiFi than an ESP8266 can handle then use a standard off the shelf wireless access point or router instead. Any decent one will handle a lot more than 8 clients.

PerryBebbington:
I don't know how to get a mesh network working but am I pointing out the obvious by suggesting that if you want more devices connected to WiFi than an ESP8266 can handle then use a standard off the shelf wireless access point or router instead. Any decent one will handle a lot more than 8 clients.

i thought about that. i want something smaller. i have multiple routers that runn ddwrt i could wire up just for this. it would also be much simpler if i could just use the WLAN for the house but i can keep track of ip addresses. i sort of just want to plug and play. at most i want to configure the ssid and pw for the master and let the master handle everything else.

i also thought about maybe programming an raspberry pi as a hotspot

I might be missing something but whether you use a WAP or the ESP8266 you still need to know at least 1 IP address. Depends what you are doing, so, what exactly are you trying to achieve and how? There might be a different approach that does what you want.