Arduino Nano ESP32 with LCD display not working

I have a Arduino Nano ESP32 with LCD Display (with onboard I2C shield). Using following code I am able to display "Hello world" on a Mega 2560 but I cant see anything on the Nano (on the nano the backlight is on and all I see is squares as seen in the screenshot):

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
//const int  en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3; //For Mega 2560
const int en = D2, rw = D1, rs = D0, d4 = D4, d5 = D5, d6 = D6, d7 = D7, bl = D3; //For Nano ESP32

 
// Define I2C Address - change if reqiuired
const int i2c_addr = 0x27;
 
//LiquidCrystal_I2C lcd(i2c_addr, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);
LiquidCrystal_I2C lcd(0x27, 16,2);

void setup(){
  // initialize LCD
  //lcd.begin();
  // turn on LCD backlight                      
  lcd.backlight();
}

void loop(){
  // set cursor to first column, first row
  lcd.setCursor(0, 0);
  // print message
  lcd.print("Hello, World!");
  delay(1000);
  // clears the display to print new message
  lcd.clear();
  // set cursor to first column, second row
  lcd.setCursor(0,1);
  lcd.print("Hello, World!");
  delay(1000);
  lcd.clear(); 
}

The Nano ESP32 is powering the LCD display via the VBUS pin. Another thing I have noticed is that if I reset or flash the nano, the display backlight turns off. In this state if I just unplug the VBUS wire and plug it back in, the display light turns on. Still no text though.
Here is how the screen looks like (Sorry the Mega is just photobombing):

Any ideas?

This is a relatively common problem for users who are not familiar with the hardware. The issue arises because the LCD requires 5V to operate properly, while the ESP runs on 3.3V, and the Mega operates on 5V. Do you see the potential conflict?

To resolve this, you need to power the display with 5V and use pull-up resistors connected to the 3.3V line. Use resistors in the range of 3kΩ to 4kΩ, which will override the possible 10kΩ pull-up resistors on the display’s backpack. This approach works because the I²C protocol supports a wide voltage range, and 3.3V falls within that range.

Keep in mind that the I²C bus is open collector/drain, meaning it doesn’t source current, this is the role of the pull-up resistors.

Thanks. I read this about the Nano ESP32: https://support.arduino.cc/hc/en-us/articles/360014779679-Enable-5-V-power-on-the-VUSB-or-VBUS-pin-on-Nano-boards
This clearly says that the VBUS pin is already 5V (provided its connected to a USB that supplies 5V - this was my case)
Also, I did try powering the LCD externally (connect the GND and VIN to an external 5V supply and the SCL and SDA to the Nano's A4/A5 pins).

Is there a potentiometer on the back of the LCD?
If so, give that a tweak one way and the other to see if it comes in.

Yeah tried that first. It only makes those square blocks brighter on the screen.

I don't know if it makes a difference in this case, but it may --
have you tried, before Uploading, selecting by Arduino pin (default) vs
by GPIO number (legacy) ?
(IOW - try both)

PE - Additionally, one way or the other - look up Wire Scan in the Examples and see how that goes (does it find any address/es).

"By Arduino pin (default)" option causes build errors for the Nano. I know the build is working as the IMU portion of the code is working. IMU seems to work on 3.3 V

What about Wave Scan ?

SO I just tried the same code with an Arduino Nano (not ESP32) from Elegoo and it worked perfectly. (Physical Pins used were also the same). Only thing I had to change is use the uncommented line:

 const int  en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3;
//const int en = D2, rw = D1, rs = D0, d4 = D4, d5 = D5, d6 = D6, d7 = D7, bl = D3;

It's very strange. But that's not I2C, which is 2 pin (sda, scl).
The RS, EN, data pins etc. are handled by the backpack.