Esp32 with 16 x 2 i2c not updating after splash scree help

LCD not updating after the initial splash text. I am trying to display a menu with several layers using an encoder. It just will not update.

#include <Wire.h>
#include <Encoder.h>
#include <EEPROM.h>
#include <USB.h>
#include <USBHIDKeyboard.h>
#include <USBHIDMouse.h>
#include <MenuSystem.h>

// Hardware Configuration
const int buttonPins[] = {48, 1, 42, 41, 13, 12, 11};  // Full set
const int numButtons = 7;
Encoder myEnc(38, 39);  // Encoder pins
const int encButton = 10;
#define I2C_ADDRESS 0x27  // Confirmed working
USBHIDKeyboard Keyboard;
USBHIDMouse Mouse;

// Profile and Shortcut Definitions
const int maxProfiles = 6;
struct Profile { 
  char name[8]; 
  int assignments[6]; 
};

Profile profiles[maxProfiles] = {
  {"Model", {0, 1, 2, 3, 4, 9}}, {"Anim", {21, 22, 23, 24, 25, 26}},
  {"Text", {5, 6, 13, 10, 12, 7}}, {"Py", {16, 19, 20, -1, -1, -1}},
  {"Mouse", {27, 28, 29, 30, 31, -1}}, {"Win", {32, 33, 34, 35, 36, 37}}
};

int currentProfile = 0;
const char* shortcutKeys[] = {"G", "S", "R", "E", "Shift+A", "Ctrl+C", "Ctrl+V", "Tab", "Alt+Z", "Ctrl+Z",
  "Ctrl+F", "Shift+Tab", "Ctrl+S", "Ctrl+X", "Ctrl+V", "Ctrl+D", "Ctrl+R", "Shift+Ctrl+C", "Alt+F", "F5",
  "Ctrl+Space", "I", "Alt+A", "Shift+Space", "Ctrl+I", "Shift+D", "Alt+I", "MMB", "Ctrl+LMB", "Shift+MMB",
  "Ctrl+WheelUp", "Ctrl+WheelDown", "Chrome", "Copy", "Paste", "Email", "Notepad", "Cmd"};
const char* shortcutNames[] = {"Move", "Scale", "Rotate", "Extrude", "Add", "Copy", "Paste", "EditMode",
  "Wireframe", "Undo", "Find", "Unfold", "Save", "Cut", "PasteTxt", "Duplicate", "RunScript", "CopyPath",
  "Format", "Reload", "AutoComp", "InsertKey", "PlayAnim", "PlaySpace", "InvertKey", "DupKey", "DelKey",
  "Orbit", "Lasso", "Pan", "ZoomIn", "ZoomOut", "Chrome", "Copy", "Paste", "Email", "Notepad", "Cmd"};
int shortcutCount = 38;

// Custom Renderer for MenuSystem (empty as we handle display ourselves)
class MyRenderer : public MenuComponentRenderer {
public:
  void render(Menu const& menu) const override {}
  void render_menu_item(MenuItem const& menu_item) const override {}
  void render_back_menu_item(BackMenuItem const& menu_item) const override {}
  void render_numeric_menu_item(NumericMenuItem const& menu_item) const override {}
  void render_menu(Menu const& menu) const override {}
};

// Function Prototypes
void lcdInit();
void lcdWriteNibble(uint8_t nibble, bool isData);
void lcdWriteByte(uint8_t data, bool isData);
void lcdClear();
void lcdSetCursor(uint8_t col, uint8_t row);
void lcdPrint(const char* str);
void sendShortcut(const char* shortcut);
void launchBlender();
void loadProfile(int profileId);
void saveProfile(int profileId);
void updateDisplayMenu();
void setupMenu();
void on_launch_selected(MenuComponent* p_menu_component);
void on_profile_selected(MenuComponent* p_menu_component);
void on_shortcut_selected(MenuComponent* p_menu_component);
void on_assign_selected(MenuComponent* p_menu_component);

// Menu System Setup
MyRenderer renderer;
MenuSystem ms(renderer);
Menu mainMenu("PrecisionDeck");
Menu profileMenu("Profiles");
Menu shortcutMenu("Shortcuts");
Menu assignMenu("Assign to");
MenuItem mi_launch("Launch Blender", &on_launch_selected);

// Variables
long oldPosition = -999;
int menuPos = 0;
bool inAssignMode = false;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
unsigned long lastDisplayUpdate = 0;
unsigned long lastSplashTime = 0;
unsigned long lastActionTime = 0;
bool displayNeedsUpdate = true;
bool splashDisplayed = false;
bool actionDisplayed = false;

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("PrecisionDeck Booting...");
  
  EEPROM.begin(512);
  for (int i = 0; i < maxProfiles; i++) {
    loadProfile(i);
  }
  
  for (int i = 0; i < numButtons; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  pinMode(encButton, INPUT_PULLUP);
  
  Wire.begin(21, 20);
  Wire.setClock(50000);
  Serial.println("Initializing LCD...");
  lcdInit();
  
  lcdClear();
  lcdSetCursor(0, 0);
  lcdPrint("PrecisionDeck");
  lcdSetCursor(0, 1);
  lcdPrint("Loading...");
  lastSplashTime = millis();
  Serial.println("LCD initialized");
  
  Serial.println("Setting up menu...");
  setupMenu();
  ms.get_root_menu().add_menu(&mainMenu);
  ms.select();
  Serial.println("Menu setup complete");
  
  Serial.println("Initializing USB...");
  USB.begin();
  Keyboard.begin();
  Mouse.begin();
  delay(200);
  
  Serial.println("Setup complete");
}

void loop() {
  if (!splashDisplayed && (millis() - lastSplashTime > 1000)) {
    Serial.println("Splash timeout, updating display...");
    updateDisplayMenu();
    splashDisplayed = true;
  }
  
  long newPosition = myEnc.read() / 4;
  if (newPosition != oldPosition) {
    Serial.println("Encoder moved");
    if (newPosition > oldPosition) ms.next();
    else ms.prev();
    oldPosition = newPosition;
    displayNeedsUpdate = true;
  }
  
  static bool lastEncButtonState = HIGH;
  bool encButtonState = digitalRead(encButton);
  if (lastEncButtonState == HIGH && encButtonState == LOW) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay && lastEncButtonState == LOW && encButtonState == HIGH) {
    Serial.println("Encoder button pressed");
    ms.select();
    displayNeedsUpdate = true;
    lastActionTime = millis();
    actionDisplayed = true;
  }
  lastEncButtonState = encButtonState;
  
  for (int i = 1; i < numButtons; i++) {
    static bool lastButtonState[numButtons] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
    bool buttonState = digitalRead(buttonPins[i]);
    if (lastButtonState[i] == HIGH && buttonState == LOW) {
      if (i-1 < 6 && profiles[currentProfile].assignments[i-1] != -1) {
        int shortcutIndex = profiles[currentProfile].assignments[i-1];
        Serial.println("Button " + String(i+1) + " pressed");
        lcdClear();
        lcdSetCursor(0, 0);
        lcdPrint(profiles[currentProfile].name);
        lcdSetCursor(0, 1);
        lcdPrint(("Btn" + String(i+1) + ": " + shortcutNames[shortcutIndex]).c_str());
        sendShortcut(shortcutKeys[shortcutIndex]);
        displayNeedsUpdate = true;
        lastActionTime = millis();
        actionDisplayed = true;
      }
    }
    lastButtonState[i] = buttonState;
  }
  
  if (digitalRead(buttonPins[0]) == LOW) {
    Serial.println("Button 1 pressed");
    launchBlender();
    displayNeedsUpdate = true;
    lastActionTime = millis();
    actionDisplayed = true;
  }
  
  if (actionDisplayed && (millis() - lastActionTime > 2000)) {
    Serial.println("Action timeout, updating display...");
    updateDisplayMenu();
    actionDisplayed = false;
  } else if (displayNeedsUpdate && (millis() - lastDisplayUpdate > 100)) {
    Serial.println("Updating display in loop...");
    updateDisplayMenu();
    lastDisplayUpdate = millis();
    displayNeedsUpdate = false;
  }
  
  yield();
}

// LCD Control Functions (unchanged from working sketch)
void lcdInit() {
  delay(50);
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(0x03 << 4 | 0x08);
  Wire.endTransmission();
  delay(5);
  lcdWriteNibble(0x03, false);
  delay(5);
  lcdWriteNibble(0x03, false);
  delay(5);
  lcdWriteNibble(0x02, false);
  delay(5);
  lcdWriteByte(0x28, false);
  lcdWriteByte(0x0C, false);
  lcdWriteByte(0x06, false);
  lcdClear();
}

void lcdWriteNibble(uint8_t nibble, bool isData) {
  uint8_t data = (nibble << 4) | 0x08;
  if (isData) data |= 0x01;
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(data | 0x04);
  Wire.endTransmission();
  delayMicroseconds(1);
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(data & ~0x04);
  Wire.endTransmission();
  delayMicroseconds(50);
}

void lcdWriteByte(uint8_t data, bool isData) {
  lcdWriteNibble(data >> 4, isData);
  lcdWriteNibble(data & 0x0F, isData);
}

void lcdClear() {
  lcdWriteByte(0x01, false);
  delay(2);
}

void lcdSetCursor(uint8_t col, uint8_t row) {
  uint8_t address = (row == 0) ? 0x00 : 0x40;
  address += col;
  lcdWriteByte(0x80 | address, false);
}

void lcdPrint(const char* str) {
  while (*str) {
    lcdWriteByte(*str++, true);
  }
}

// PrecisionDeck Functions
void setupMenu() {
  Serial.println("Adding profiles...");
  for (int i = 0; i < maxProfiles; i++) {
    profileMenu.add_item(new MenuItem(profiles[i].name, &on_profile_selected));
  }
  Serial.println("Adding shortcuts...");
  for (int i = 0; i < shortcutCount; i++) {
    shortcutMenu.add_item(new MenuItem(shortcutNames[i], &on_shortcut_selected));
  }
  Serial.println("Adding assignments...");
  for (int i = 1; i < numButtons; i++) {
    String btnName = "Button " + String(i+1);
    char* btnNameChar = new char[btnName.length() + 1];
    strcpy(btnNameChar, btnName.c_str());
    assignMenu.add_item(new MenuItem(btnNameChar, &on_assign_selected));
    delete[] btnNameChar;
  }
  mainMenu.add_menu(&profileMenu);
  mainMenu.add_menu(&shortcutMenu);
  mainMenu.add_menu(&assignMenu);
  mainMenu.add_item(&mi_launch);
}

void updateDisplayMenu() {
  lcdClear();
  Menu const* cp_menu = ms.get_current_menu();
  if (cp_menu == nullptr) {
    Serial.println("Error: Current menu is null");
    lcdPrint("Menu Error");
    return;
  }
  MenuComponent const* cp_menu_component = cp_menu->get_current_component();
  if (cp_menu_component == nullptr) {
    Serial.println("Error: Current menu component is null");
    lcdPrint("Component Error");
    return;
  }
  lcdSetCursor(0, 0);
  lcdPrint(cp_menu->get_name());
  lcdSetCursor(0, 1);
  lcdPrint("> ");
  lcdPrint(cp_menu_component->get_name());
  Serial.println("Display updated: " + String(cp_menu->get_name()) + " > " + String(cp_menu_component->get_name()));
}

void on_profile_selected(MenuComponent* p_menu_component) {
  MenuItem* p_menu_item = (MenuItem*)p_menu_component;
  for (int i = 0; i < maxProfiles; i++) {
    if (strcmp(p_menu_item->get_name(), profiles[i].name) == 0) {
      currentProfile = i;
      break;
    }
  }
  lcdClear();
  lcdSetCursor(0, 0);
  lcdPrint("Profile Set:");
  lcdSetCursor(0, 1);
  lcdPrint(profiles[currentProfile].name);
  displayNeedsUpdate = true;
}

void on_shortcut_selected(MenuComponent* p_menu_component) {
  MenuItem* p_menu_item = (MenuItem*)p_menu_component;
  for (int i = 0; i < shortcutCount; i++) {
    if (strcmp(p_menu_item->get_name(), shortcutNames[i]) == 0) {
      menuPos = i;
      inAssignMode = true;
      break;
    }
  }
  lcdClear();
  lcdSetCursor(0, 0);
  lcdPrint(("Assign: " + String(shortcutNames[menuPos])).c_str());
  lcdSetCursor(0, 1);
  lcdPrint("Press Btn 2-7");
  
  unsigned long startTime = millis();
  while (millis() - startTime < 5000 && inAssignMode) {
    for (int i = 1; i < numButtons; i++) {
      if (digitalRead(buttonPins[i]) == LOW) {
        profiles[currentProfile].assignments[i-1] = menuPos;
        saveProfile(currentProfile);
        lcdClear();
        lcdSetCursor(0, 0);
        lcdPrint(("Assigned to Btn" + String(i+1)).c_str());
        lcdSetCursor(0, 1);
        lcdPrint(shortcutNames[menuPos]);
        inAssignMode = false;
        displayNeedsUpdate = true;
        break;
      }
    }
    yield();
  }
  if (inAssignMode) {
    lcdClear();
    lcdSetCursor(0, 0);
    lcdPrint("Assignment");
    lcdSetCursor(0, 1);
    lcdPrint("Cancelled");
    inAssignMode = false;
    displayNeedsUpdate = true;
  }
}

void on_assign_selected(MenuComponent* p_menu_component) {
  MenuItem* p_menu_item = (MenuItem*)p_menu_component;
  int buttonIndex = -1;
  for (int i = 1; i < numButtons; i++) {
    String buttonName = "Button " + String(i+1);
    if (strcmp(p_menu_item->get_name(), buttonName.c_str()) == 0) {
      buttonIndex = i;
      break;
    }
  }
  if (buttonIndex >= 1) {
    int assignedShortcut = profiles[currentProfile].assignments[buttonIndex-1];
    lcdClear();
    lcdSetCursor(0, 0);
    lcdPrint(("Btn" + String(buttonIndex+1) + " to:").c_str());
    lcdSetCursor(0, 1);
    if (assignedShortcut != -1) lcdPrint(shortcutNames[assignedShortcut]);
    else lcdPrint("None");
    displayNeedsUpdate = true;
  }
}

void on_launch_selected(MenuComponent* p_menu_component) {
  launchBlender();
}

void loadProfile(int profileId) {
  int baseAddr = profileId * 15;
  for (int i = 0; i < 6; i++) {
    profiles[profileId].assignments[i] = EEPROM.read(baseAddr + i);
    if (profiles[profileId].assignments[i] >= shortcutCount) {
      profiles[profileId].assignments[i] = -1;
    }
  }
  Serial.println("Loaded profile: " + String(profiles[profileId].name));
}

void saveProfile(int profileId) {
  int baseAddr = profileId * 15;
  for (int i = 0; i < 6; i++) {
    EEPROM.write(baseAddr + i, profiles[profileId].assignments[i]);
  }
  EEPROM.commit();
  Serial.println("Saved profile: " + String(profiles[profileId].name));
}

void sendShortcut(const char* shortcut) {
  if (strcmp(shortcut, "G") == 0) Keyboard.write('g');
  else if (strcmp(shortcut, "S") == 0) Keyboard.write('s');
  else if (strcmp(shortcut, "R") == 0) Keyboard.write('r');
  else if (strcmp(shortcut, "E") == 0) Keyboard.write('e');
  else if (strcmp(shortcut, "Shift+A") == 0) { Keyboard.press(KEY_LEFT_SHIFT); Keyboard.write('a'); Keyboard.release(KEY_LEFT_SHIFT); }
  else if (strcmp(shortcut, "Ctrl+C") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('c'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Ctrl+V") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('v'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Tab") == 0) Keyboard.write(KEY_TAB);
  else if (strcmp(shortcut, "Alt+Z") == 0) { Keyboard.press(KEY_LEFT_ALT); Keyboard.write('z'); Keyboard.release(KEY_LEFT_ALT); }
  else if (strcmp(shortcut, "Ctrl+Z") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('z'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Ctrl+F") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('f'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Shift+Tab") == 0) { Keyboard.press(KEY_LEFT_SHIFT); Keyboard.write(KEY_TAB); Keyboard.release(KEY_LEFT_SHIFT); }
  else if (strcmp(shortcut, "Ctrl+S") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('s'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Ctrl+X") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('x'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Ctrl+D") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('d'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Ctrl+R") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('r'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Shift+Ctrl+C") == 0) { Keyboard.press(KEY_LEFT_SHIFT); Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('c'); Keyboard.releaseAll(); }
  else if (strcmp(shortcut, "Alt+F") == 0) { Keyboard.press(KEY_LEFT_ALT); Keyboard.write('f'); Keyboard.release(KEY_LEFT_ALT); }
  else if (strcmp(shortcut, "F5") == 0) Keyboard.write(KEY_F5);
  else if (strcmp(shortcut, "Ctrl+Space") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write(' '); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "I") == 0) Keyboard.write('i');
  else if (strcmp(shortcut, "Alt+A") == 0) { Keyboard.press(KEY_LEFT_ALT); Keyboard.write('a'); Keyboard.release(KEY_LEFT_ALT); }
  else if (strcmp(shortcut, "Shift+Space") == 0) { Keyboard.press(KEY_LEFT_SHIFT); Keyboard.write(' '); Keyboard.release(KEY_LEFT_SHIFT); }
  else if (strcmp(shortcut, "Ctrl+I") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('i'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Shift+D") == 0) { Keyboard.press(KEY_LEFT_SHIFT); Keyboard.write('d'); Keyboard.release(KEY_LEFT_SHIFT); }
  else if (strcmp(shortcut, "Alt+I") == 0) { Keyboard.press(KEY_LEFT_ALT); Keyboard.write('i'); Keyboard.release(KEY_LEFT_ALT); }
  else if (strcmp(shortcut, "MMB") == 0) Mouse.click(MOUSE_MIDDLE);
  else if (strcmp(shortcut, "Ctrl+LMB") == 0) { Mouse.press(MOUSE_LEFT); Keyboard.press(KEY_LEFT_CTRL); Mouse.release(MOUSE_LEFT); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Shift+MMB") == 0) { Mouse.press(MOUSE_MIDDLE); Keyboard.press(KEY_LEFT_SHIFT); Mouse.release(MOUSE_MIDDLE); Keyboard.release(KEY_LEFT_SHIFT); }
  else if (strcmp(shortcut, "Ctrl+WheelUp") == 0) { Keyboard.press(KEY_LEFT_CTRL); Mouse.move(0, 0, 10); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Ctrl+WheelDown") == 0) { Keyboard.press(KEY_LEFT_CTRL); Mouse.move(0, 0, -10); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Chrome") == 0) Keyboard.println("\"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\"");
  else if (strcmp(shortcut, "Copy") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('c'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Paste") == 0) { Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('v'); Keyboard.release(KEY_LEFT_CTRL); }
  else if (strcmp(shortcut, "Email") == 0) Keyboard.println("\"C:\\Program Files\\Microsoft Office\\root\\Office16\\OUTLOOK.EXE\"");
  else if (strcmp(shortcut, "Notepad") == 0) Keyboard.println("notepad.exe");
  else if (strcmp(shortcut, "Cmd") == 0) Keyboard.println("cmd.exe");
  Serial.println("Sent shortcut: " + String(shortcut));
}

void launchBlender() {
  lcdClear();
  lcdSetCursor(0, 0);
  lcdPrint("Launching");
  lcdSetCursor(0, 1);
  lcdPrint("Blender...");
  Keyboard.press(KEY_LEFT_GUI);
  Keyboard.press('r');
  Keyboard.releaseAll();
  Keyboard.println("\"C:\\Program Files\\Blender Foundation\\Blender 4.3\\blender.exe\"");
  Serial.println("Launching Blender");
  displayNeedsUpdate = true;
}

}

I can see there is no loop function in your code. For continuous updating, shouldn't there be a loop function?

Use a well-known, well-tested library for your LCD, instead of trying to roll your own. Try that later if you want, but, once you get the code working with a known working library.

Also please always post your code in full, otherwise forum members will naturally assume the problem is in the part you didn't post, plus they won't be able to test it for you.