See bottom for solution.

I am trying to run the Arduino LiquidCrystal library example HelloWorld.ino on an ESP32. It seems like it never even executes the Setup() loop. The ESP resets after eight seconds and then repeats the cycle.

I have used character LCD many times before (with Arduino) but always using I2C. For the current design I am eliminating the I2C to parallel chip and I am instead driving the LCD directly from the ESP32. I am using 4 bit mode to reduce the number of pins required. I have connected Register select, Enable, and D4-D7. These details are not relevant since the ESP32 does not even run with the LiquidCrystal library.

I have looked at the library code and I didn't see anything that I thought would be a problem. But I am a hardware designer (for 36 years) and not a programmer. I use the Arduino IDE because it is quick and easy to test hardware.

The library code can be found here. https://github.com/arduino-libraries/LiquidCrystal/tree/master/src

This is what I get from the serial monitor.

configsip: 0, SPIWP:0xee
mode:DIO, clock div:1
entry 0x400805f8
ets Jun  8 2016 00:22:57

I tried the example code, and when that didn't work so I added a couple of serial print lines to the code. I am listing that below.

#include <LiquidCrystal.h>

const int rs = 26, en = 25, d4 = 16, d5 = 17, d6 = 18, d7 = 19;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  lcd.begin(16, 2);
  lcd.print("hello, world!");

void loop() {
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);
  Serial.println(millis() / 1000);

Details that I didn't list above. I am powering the LCD from 5 volts. The LCD data/control lines are specified as VinLo = 0.55v and VinHi = 2.4 volts. Not that this matters since the code above never executes. I have used a Arduino Nano powered with 3.3 volts, running the above code, to confirm that the display actually works under these conditions. I really want this to work with an ESP32-C3. I tried that originally but switched to the ESP32 because it wasn't working with the code.

I hope someone can provide some guidance here. My other option is not using the library and writing my own code, which ends up being brute force and simplistic.


A big thanks to Majenko who was spot on. After removal of the call the code executed properly.

  • 1
    My guess: the constructor calls ::init(). ::init() calls ::begin(). ::begin() uses delays. Those delays may depend on things that aren't configured yet when the constructors are running, and lock up causing a WDT. That library looks to be poorly written TBH. Remove the call to begin() in the ::init() function.
    – Majenko
    Nov 6, 2021 at 21:51
  • I just recently was having a similar issue. I was trying to get the I2C display to work on an ESP32 using the adafruit library, without success. I then went ahead and used another LCD library. (Debugging the library was out of scope for me, since all I wanted to do was test the I2C bus).
    – PMF
    Nov 7, 2021 at 7:41
  • Tipp: Install github.com/me-no-dev/EspExceptionDecoder. You can then paste the line that says "Backtrace" from the ESP32 crash dump into that tool and get a nice stack trace. Very helpful.
    – PMF
    Nov 7, 2021 at 7:45
  • @PMF The code did not execute so there was no backtrace to examine. Majenko was spot on with his comment to "Remove the call to begin() in the ::init() function." I removed that call and now the code executes and works properly.
    – Rudy
    Nov 7, 2021 at 19:28

1 Answer 1


My guess:

  • the constructor calls LiquidCrystal::init().
  • LiquidCrystal::init() calls LiquidCrystal::begin().
  • LiquidCrystal::begin() uses delays.

Those delays may depend on things that aren't configured yet when the constructors are running, and lock up causing a WDT.

Remove the call to begin() in the LiquidCrystal::init() function and it should at least get past running the constructor so it gets to run the rest of your code.

Quite why they have that call in there is beyond me. Rule number one of writing an Arduino library: never perform any operations more strenuous than assigning variables in the constructor as resources you may rely on may not have been initialized yet.

  • I guess the reason was that they wanted the display to also work if you don't call begin() in setup(). The AVR boards have no exception handling, so the general rule seems to be "Let's always do a best guess what the user wanted when something is not right"
    – PMF
    Nov 7, 2021 at 20:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.