1

I'm trying to upload a script to my ESP32 DOIT board through Arduino IDE. tl;dr: I'm trying to get a string from a webform and print it on a 0.96" OLED display.

The code I'm using is a combination of two scripts: the first one was a tutorial about hosting a webserver with input html forms in an ESP32 and the second was the OLED SSD1306 example from the Adafruit Library.

The final code I'm using is:

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

AsyncWebServer server(80);

// I REPLACED WITH MY NETWORK CREDENTIALS
const char* ssid = "my_ssid";
const char* password = "mypassword";

const char* PARAM_INPUT_1 = "input1";

// HTML web page to handle 3 input fields (input1, input2, input3)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
  <title>ESP Input Form</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head><body>
  <form action="/get">
    input1: <input type="text" name="input1">
    <input type="submit" value="Submit">
  </form><br>
</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });

  // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      inputParam = PARAM_INPUT_1;
    }
    else {
      inputMessage = "No message sent";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/html", "HTTP GET request sent to your ESP on input field (" 
                                     + inputParam + ") with value: " + inputMessage +
                                     "<br><a href=\"/\">Return to Home Page</a>");

    delay(2000);
    display.clearDisplay();

    display.setTextSize(5);
    display.setTextColor(WHITE);
    display.setCursor(0, 10);

    display.println(inputMessage);
    display.display();
    delay(5000);
    display.clearDisplay();
    display.display();                                 
  });
  server.onNotFound(notFound);
  server.begin();
}

void loop() {
  
}

The code uploads just fine, but in Serial Monitor I get the message:

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x400dafd2  PS      : 0x00060d30  A0      : 0x800d2add  A1      : 0x3ffb27a0  
A2      : 0x3ffc2d6c  A3      : 0x000001ff  A4      : 0x00000000  A5      : 0x00000001  
A6      : 0x0000ffff  A7      : 0x0000007f  A8      : 0x800daf9f  A9      : 0x3ffb2780  
A10     : 0x3ffc2f10  A11     : 0x00000040  A12     : 0x4014bb80  A13     : 0x00000006  
A14     : 0x000000ff  A15     : 0x4014bb80  SAR     : 0x0000000a  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x40089a95  LEND    : 0x40089aa5  LCOUNT  : 0xfffffffe  


Backtrace:0x400dafcf:0x3ffb27a00x400d2ada:0x3ffb27d0 0x400dd3b2:0x3ffb2820 

ELF file SHA256: 0000000000000000

Rebooting...

I tried 3 of my ESP32 boards and everytime I get the same message. When I remove the part where I print my string on the display, there's (obviously) no error.

Can you please point out how to overcome this problem? Why using each part of my code seperately works, but combining them doesn't work?

Thank you in advance!

Panos Fusu
  • 11
  • 3
  • Did you first try just one of the tutorial apps first to make sure you can get that working on your system? Is there anything on the serial console printed out before what you are showing? – lurker Nov 13 '22 at 22:19
  • Dear lurker, thank you for your comment. Yes I tried both of these examples seperately and everything worked fine. There's nothing else printed on the serial monitor except the local IP Address that's assigned to the webserver – Panos Fusu Nov 13 '22 at 22:23
  • You could try adding some serial console messages to see how far it's getting in your code before it fails. The LoadProhibited occurs due to an invalid address access. I see you access several pointers without checking of any are null. – lurker Nov 13 '22 at 22:24

2 Answers2

2

Your code is using ESPAsyncWebServer.

Your callback for "/get" calls delay(). This is explicitly forbidden in the ESPAsyncWebServer README:

You can not use yield or delay or any function that uses them inside the callbacks

Your callback also does quite a bit of computation, calling 3rd party libraries that you can't be sure are safe to call here.

You need to rewrite the callback. Instead of doing work there, save the message you want to display in a variable and set a boolean variable indicating there's work to be done. Then in loop(), when the boolean is true, do the work that the callback did and clear the flag indicating there was work to be done.

For instance, your new code might look something like this:

boolean show_message = false;
String input_message;

void setup() {
  ...

  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputParam;
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      inputParam = PARAM_INPUT_1;
    }
    else {
      inputMessage = "No message sent";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/html", "HTTP GET request sent to your ESP on input field (" 
                                     + inputParam + ") with value: " + inputMessage +
                                     "<br><a href=\"/\">Return to Home Page</a>");
    show_message = true;
    }

    ...
}

void loop() {
  if(show_message) {
    // code to do the work goes here

    show_message = false;
  }
}
romkey
  • 6,218
  • 3
  • 16
  • 12
  • Dear romkey, thank you for your detailed answer. You really helped me. I don't know what I was thinking when I was writing the callback. I found a lot of info online on how to do it correctly. I also tried what you suggested and removed all 3rd party libraries. However it seems that I didn't do everything the right way. I already have the message I want to display stored inside a var (inputMessage). I'm not sure though how to use the boolean you mentioned. Can you please point out an example?? I'm not sure I'm googling right for this one (aka the use of a boolean inside a callback). – Panos Fusu Nov 14 '22 at 00:26
  • I updated the answer to show how to restructure the code. – romkey Nov 14 '22 at 00:38
  • Thanks once again for your advice! I followed your suggestions and it seems that you helped me to make progress. Now the code runs until the point that I get a local IP and I can print a string on my serial monitor but NOT on my oled display. The board crushes when I enter the for loop. It seems that there's a problem with the adafruit library maybe(??). I haven't imagined that it would be so hard (at least for a noob like me) to print string on oled displays through a webform.. – Panos Fusu Nov 14 '22 at 09:45
  • @PanosFusu Stack Overflow works best when there's one question per post, and not when there are questions in comments. If my answer solved the problem the best thing to do is to accept it as a solution so that other people with similar problems can see that it worked, and then post your new question as a new post. This lets other people benefit from its solution when it's solved, and lets other people who might be able to help see it, which they won't if it's here in comments. – romkey Nov 14 '22 at 15:46
-1

It seems that this famous project does exactly what I was trying to do and it works like a charm.

Panos Fusu
  • 11
  • 3