ESP Abstürze treiben mich in den Wahnsinn

Hallo zusammen,

seit Stunden versuche ich einem ESP Absturz auf die Schliche zu kommen.
Ich habe einen WebServer programmiert, der mir alle verfügbaren WiFi anzeigt.
Die Probleme fingen an, als ich versucht habe die Ausgabe in HTML etwas netter zu gestalten.

Wenn ich nur ein einziges Zeichen in den HTML Code zusätzlich einfüge, crasht der ESP beim Aufruf der Seite.

Hier das Hauptprogramm

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#include "html.h"

const char* ssid = "********";
const char* password = "++++++++";

void setup(void) {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }

  server.on("/", []()
  {
    int wifiFound = WiFi.scanNetworks();
    String enc;
    String item = HTTP_SELECT;
    item.replace("{n}", String(wifiFound, DEC));
    server.setContentLength(CONTENT_LENGTH_UNKNOWN);
    server.send(200, "text/html", "");
    server.setContentLength(CONTENT_LENGTH_UNKNOWN);
    server.sendContent(item);
    delay(0);

    // scan for networks
    Serial.println("scan done");
    if (wifiFound == 0)
      Serial.println("no networks found");
    else
    {
      Serial.print(wifiFound);
      Serial.println(" networks found");
    }
    item = HTTP_TABROW;
    for (int i = 0; i < wifiFound; ++i)
    {        // Print SSID and RSSI for each network found
        Serial.print(i + 1);
        Serial.print(": ");
        Serial.print(WiFi.SSID(i));
        Serial.print(" (");
        Serial.print(WiFi.RSSI(i));
        Serial.print(") ");
        Serial.println(WiFi.encryptionType(i));
        /*
          ENC_TYPE_UNKNOWN  = 0,
          ENC_TYPE_WEP  = 5,
          ENC_TYPE_TKIP = 2,
          ENC_TYPE_CCMP = 4,
          ENC_TYPE_NONE = 7,
          ENC_TYPE_AUTO = 8
          */
      item = HTTP_TABROW;  //<tr><td>{n}:{s} ({r}) {e}</td></tr>
      item.replace("{n}", String(i + 1, DEC));
      item.replace("{s}", String(WiFi.SSID(i)));
      item.replace("{r}", String(WiFi.RSSI(i)));
      item.replace("{e}", String(WiFi.encryptionType(i),DEC));
      server.sendContent(item);
      delay(0);
    }
    server.client().stop();
  });
  
  server.onNotFound ( handleNotFound );
  server.begin();
  Serial.println ( "HTTP server started" );
}

void loop(void) {
  server.handleClient();
}

… und als include der html code im zusätzlichen TAB

ESP8266WebServer server(80);

const char HTTP_SELECT[] PROGMEM = "<center>{n} networks found

<table><tbody>";
const char HTTP_TABROW[] PROGMEM = "<tr><td>{n}: {s} ({r}) {e}</td></tr>";
const char HTTP_TABFOOT[] PROGMEM = "</tbody></table></center>";

void handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

Wenn ich jetzt in der Ausgabe nur ein einziges Zeichen hinzufüge, crasht der ESP beim Aufruf, also zB statt

const char HTTP_TABROW PROGMEM = “{n} {s} ({r}) {e}”;

füge ich den Doppelpunkt hinzu

const char HTTP_TABROW PROGMEM = “{n}: {s} ({r}) {e}”;

Ich habs auch schon mit zusätzlichem delay(1) zwischen den replace Befehlen versucht, nützt auch nichts.

Eigentlich wollte ich eine Tabelle für die Ausgabe so richtig nett mit Rahmen,

Hier die Crash Info des ESP

Exception (3):
epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x4023575d depc=0x00000000

ctx: cont 
sp: 3fff0a10 end: 3fff0d20 offset: 01a0

>>>stack>>>
3fff0bb0:  00000001 00000001 3fff0c10 4020c5fc  
3fff0bc0:  4023575d 00000000 3fff0000 4020c526  
3fff0bd0:  00000001 00000001 3fff2310 40206c46  
3fff0be0:  0000000a 3fff0cd0 3fff0c20 4020c5ae  
3fff0bf0:  3fff1fb8 4010683a 3fff0c60 00000001  
3fff0c00:  3ffefa7c 00000000 00000000 00000000  
3fff0c10:  3fff1fc8 0000000f 00000000 4020c57e  
3fff0c20:  3fff1f80 0000000f 3fff0c60 4020c5ae  
3fff0c30:  4010684c 3fff2310 3fff0c60 00000001  
3fff0c40:  00000001 00000001 3fff2310 40208536  
3fff0c50:  40208540 3fff2310 3fff0c80 40208572  
3fff0c60:  3fff1fc8 0000000f 00000001 4020c6d4  
3fff0c70:  40208540 3fff2310 3ffef1b8 4020872d  
3fff0c80:  3fff1f80 0000000f 00000001 402076ff  
3fff0c90:  3ffef1f4 00000013 3fff0cd0 00000001  
3fff0ca0:  00000000 0000000a 000003e8 4020b8e1  
3fff0cb0:  00000000 3fff24d8 3fff0d6c 3ffefcf4  
3fff0cc0:  3fffdc20 000003e9 3ffef1b8 40208828  
3fff0cd0:  3ffe8610 00000000 000003e8 00007456  
3fff0ce0:  3ffef1d8 3fff24d8 00000016 40101941  
3fff0cf0:  4020affd 00000000 3ffefcec 40206b94  
3fff0d00:  3fffdc20 00000000 3ffefcec 4020b025  
3fff0d10:  00000000 00000000 3ffefd00 40100114  
<<<stack<<<

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


 ets Jan  8 2013,rst cause:4, boot mode:(1,7)

wdt reset

Wer weiß Rat.

Gruß
Reinhard

Hast aber auch eine komplizierte Message....

Programmierst Du den ESP oder einen Arduino?
Grüße Uwe

uwefed:
Programmierst Du den ESP oder einen Arduino?
Grüße Uwe

Äh, mmh, rhetorische Frage ? Falsches Forum ?
Ich programmiere den ESP direkt mit der Arduino IDE

stoni99:
Hast aber auch eine komplizierte Message....

Wieso kompliziert? Das ist hmtl-technisch eine einfache Tabelle mit mehreren Zeilen. -> Anleitung
Schwierig sieht es vielleicht deshalb aus, weil ich Platzhalter mit den dynamischen Inhalten ersetze.

Thema ist anscheinend gelöst.

Das eigentliche Problem verursachte der String.replace() Befehl in Verbindung mit der Zuweisung aus PROGMEM.

Nachdem ich den String mit

String item = FPSTR(HTTP_TABROW);

zugewiesen habe, funktioniert es. Hängt wohl irgendwie mit der Speicher Allockierung zusammen, so richtig verstanden habe ich das nicht.

Wenn Interesse am fertigen Code besteht, stelle ich den gerne zur Verfügung.

Das ist auch logisch. Ein PROGMEM String ist letztlich auch nur ein const char*. C++ hat keinerlei Möglichkeit zu unterscheiden ob der String jetzt im Flash steht oder ob es ein const Zeiger auf RAM ist. Die String Klasse ruft dann eine Methode auf die Speicher im RAM erwartet, aber dort steht Müll, weil die Daten wirklich im Flash sind.

Deshalb gibt es da in der IDE so Tricksereien wie FlashStringHelper, was nur die Vorrausdeklaration einer Klasse ist. Dann kann man einen const char* darauf casten und die String Klasse kann per überladenen Funktionen feststellen was nun eigentlich gemeint ist.

Ich habe den const char PROGMEM ja vor der Anwendung der String Operation in eine String Variable kopiert. Was passiert denn da im Hintergrund?