Help with lvgl crahes after connecting to Access point

What do you want to achieve?

i want to be able to connect to AP(right now that part covered), and once connected, the screen of CrowPanel 2.4 inch goes to a new screen(success screen). But, i see a white screen after connecting.

i also added the important files of the existing code, please help. tried everything and watched a lot of youtube videos. none explain this…

What have you tried so far?

i’ve tried to call the function to switch screens in many different spots in code.

Screenshot or video

whats happening when connecting to AP:

Code

.ino file:

#include "HX711.h"
#include <TFT_eSPI.h>
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
using fs::FS;
#include <WebServer.h>             // For captive portal
#include <DNSServer.h>  
/**************************TFT_eSPI************************
If you don't know how to configure TFT_eSPI library for the display and touch driver
Please refer to the content of the fifth lesson
**************************************************************/
#include <Arduino.h>
#include <SPI.h>

/**************************LVGL and UI************************
if you want to use the LVGL demo. you need to include <demos/lv_demos.h> and <examples/lv_examples.h>. 
if not, please do not include it. It will waste your Flash space.
**************************************************************/
#include <lvgl.h>
#include "ui.h"
/**************************LVGL and UI END************************/

// get ui_activate_button from ui.h


// HX711 pins
const int HX711_DOUT = 25;
const int HX711_SCK = 32;



// define scale variable, to use also outside of App_touch_screen.ino
HX711 scale;

// WiFi & Setup Credentials
String wifiSsid         = "";
String wifiPass         = "";
String hotspotSsid      = "";
String hotspotPass      = "";

// AP & Setup credentials
const char* AP_SSID = "WeightOut";
IPAddress local_IP(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
WiFiServer server(80);


bool phoneConnected = false;

String API_KEY              = "AIzaSyA3P9h-w1mSUYyM_0h_X_GA61-HxOVbL8w";
String BACKEND_URL          = "https://weighout-v1000-default-rtdb.europe-west1.firebasedatabase.app";




/*******************************************************************************
 * Please define the corresponding macros based on the board you have purchased.
 * CrowPanel_24 means CrowPanel ESP32 HMI 2.4inch Board
 * CrowPanel_28 means CrowPanel ESP32 HMI 2.8inch Board
 * CrowPanel_35 means CrowPanel ESP32 HMI 3.5inch Board
 ******************************************************************************/
#define CrowPanel_24
//#define CrowPanel_28
//#define CrowPanel_35

static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 240;
uint16_t calData[5] = { 557, 3263, 369, 3493, 3  };



TFT_eSPI lcd = TFT_eSPI(); /* TFT entity */

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[ screenWidth * screenHeight / 13 ];

//_______________________
/* display flash */
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
  uint32_t w = ( area->x2 - area->x1 + 1 );
  uint32_t h = ( area->y2 - area->y1 + 1 );

  lcd.startWrite();
  lcd.setAddrWindow( area->x1, area->y1, w, h );
  lcd.pushColors( ( uint16_t * )&color_p->full, w * h, true );
  lcd.endWrite();

  lv_disp_flush_ready( disp );
}

uint16_t touchX, touchY;
/*touch read*/
void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{

  bool touched = lcd.getTouch( &touchX, &touchY, 600);
  if ( !touched )
  {
    data->state = LV_INDEV_STATE_REL;
  }
  else
  {
    data->state = LV_INDEV_STATE_PR;

    /*set location*/
    data->point.x = touchX;
    data->point.y = touchY;

    // get presssure 
    //uint16_t pressure = lcd.getTouchRawZ();
    //Serial.print( "Pressure: " );
    //Serial.println( pressure );

    Serial.print( "Data x " );
    Serial.println( touchX );

    Serial.print( "Data y " );
    Serial.println( touchY );
  }
}

extern "C" void reset_weight(lv_event_t * e) {
  Serial.println("[INFO] Taring scale...");
  scale.tare();
  Serial.println("[INFO] Scale tared.");
}

extern "C" void AP_on(lv_event_t * e) {
  Serial.println("[INFO] Starting WiFi Access Point...");
  
  // Set up the Access Point
  WiFi.mode(WIFI_AP);

  //Configure AP parameters
  WiFi.softAPConfig(local_IP, gateway, subnet);
  WiFi.softAP(AP_SSID);

  server.begin();

  Serial.println("[INFO] Captive portal started!");
}

extern "C" void AP_off(lv_event_t * e) {
  Serial.println("[INFO] Stopping WiFi Access Point...");
  
  // Stop the Access Point
  WiFi.softAPdisconnect(true);
  WiFi.mode(WIFI_STA);

  // Stop the server
  server.stop();
  

  Serial.println("[INFO] Captive portal stopped!");

  // Restart the ESP32
  ESP.restart();
}



void setup()
{
  Serial.begin( 115200 ); /*serial init */

  //Port_D
  pinMode(25, OUTPUT);
  digitalWrite(25, LOW);

  //LCD init
  lcd.begin();          
  lcd.setRotation(1); 
  lcd.fillScreen(TFT_BLACK);
  lcd.setTouch(calData);
  delay(100);
  //background light pin
  pinMode(27, OUTPUT);
  digitalWrite(27, HIGH);

  //lvgl init
  lv_init();
  
  lv_disp_draw_buf_init( &draw_buf, buf1, NULL, screenWidth * screenHeight / 13 );

  /* Initialize the display */
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init( &disp_drv );
  /* Change the following line to your display resolution */
  disp_drv.hor_res = screenWidth;
  disp_drv.ver_res = screenHeight;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register( &disp_drv );

  /* Initialize the (dummy) input device driver */
  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init( &indev_drv );
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = my_touchpad_read;
  lv_indev_drv_register( &indev_drv );

  lcd.fillScreen(TFT_BLACK);

  ui_init();

  // Scale ratio (example, adjust based on your calibration)
  float scaleRatio = 16676.0;

  // Initialize scale
  scale.begin(HX711_DOUT, HX711_SCK);
  scale.set_scale(scaleRatio);
  scale.tare();
  Serial.println("Scale initialized and tared.");

  Serial.println( "Setup done" );
}


unsigned long lastLVGL = 0;

void loop() {
  unsigned long now = millis();

  // Run LVGL handler every 5 ms
  if (now - lastLVGL > 5) {
    lv_timer_handler();
    lastLVGL = now;
  }

  // Read scale every 200 ms (or as needed)
  static unsigned long lastScaleRead = 0;
  if (now - lastScaleRead > 500) {
    float measured_weight = scale.get_units(10);

    if (measured_weight < 0) {
      measured_weight = 0.0;
    }

    //Serial.print("Weight: ");
    //Serial.println(measured_weight, 3);

    char weight_str[16];
    snprintf(weight_str, sizeof(weight_str), "%.3f", measured_weight);
    lv_label_set_text(ui_weight, weight_str);

    lastScaleRead = now;
  }

  static bool qrScreenCreated = false;
  if (WiFi.getMode() == WIFI_AP) {
    int numStations = WiFi.softAPgetStationNum();
    if (numStations > 0 && !phoneConnected) {
        phoneConnected = true;
        Serial.println("[INFO] Phone connected. Switching to QR code screen.");

        if (!qrScreenCreated) {
            ui_qr_code_screen_init();  // Create the QR code screen only once
            qrScreenCreated = true;
        }
        lv_scr_load(ui_qr_code);
        //lv_obj_invalidate(ui_qr_code);
    }
  } else if (WiFi.getMode() == WIFI_AP && WiFi.softAPgetStationNum() == 0) {
    phoneConnected = false;
    Serial.println("[INFO] No phone connected; resetting phoneConnected flag.");
  }
  


  //lv_timer_handler();
  delay(5);
}

ui.c:

// This file was generated by SquareLine Studio

// SquareLine Studio version: SquareLine Studio 1.5.1

// LVGL version: 8.3.11

// Project name: SquareLine_Project

#include "ui.h"

#include "ui_helpers.h"

///////////////////// VARIABLES ////////////////////

// SCREEN: ui_Mainscreenwithoutfriens

void ui_Mainscreenwithoutfriens_screen_init(void);

lv_obj_t *ui_Mainscreenwithoutfriens;

lv_obj_t *ui_wifi;

lv_obj_t *ui_home_symbol;

lv_obj_t *ui_weight;

void ui_event_resetbutton( lv_event_t * e);

lv_obj_t *ui_resetbutton;

lv_obj_t *ui_Label1;

void ui_event_addfriendsbutton( lv_event_t * e);

lv_obj_t *ui_addfriendsbutton;

lv_obj_t *ui_Add_Friends;

void ui_event_send_button( lv_event_t * e);

lv_obj_t *ui_send_button;

lv_obj_t *ui_send;

lv_obj_t *ui_Home_label;

// CUSTOM VARIABLES

lv_obj_t *uic_Screen1;

// SCREEN: ui_casual_friends

void ui_casual_friends_screen_init(void);

void ui_event_casual_friends( lv_event_t * e);

lv_obj_t *ui_casual_friends;

lv_obj_t *ui_Cencel;

void ui_event_Cancel_button( lv_event_t * e);

lv_obj_t *ui_Cancel_button;

lv_obj_t *ui_Done;

void ui_event_Done_button( lv_event_t * e);

lv_obj_t *ui_Done_button;

lv_obj_t *ui_casual;

lv_obj_t *ui_friends_counter;

void ui_event_plus_buttun( lv_event_t * e);

lv_obj_t *ui_plus_buttun;

void ui_event_minus_button( lv_event_t * e);

lv_obj_t *ui_minus_button;

lv_obj_t *ui_plus_label;

lv_obj_t *ui_minus_label;

lv_obj_t *ui_Button8;

// CUSTOM VARIABLES

// SCREEN: ui_activate_wifi

void ui_activate_wifi_screen_init(void);

lv_obj_t *ui_activate_wifi;

lv_obj_t *ui_wifi1;

lv_obj_t *ui_home_symbol1;

lv_obj_t *ui_Home_label1;

lv_obj_t *ui_no_wifi_image;

void ui_event_activate_button( lv_event_t * e);

lv_obj_t *ui_activate_button;

lv_obj_t *ui_activate_label;

lv_obj_t *ui_explain_label;

// CUSTOM VARIABLES

// SCREEN: ui_deactivate_wifi

void ui_deactivate_wifi_screen_init(void);

lv_obj_t *ui_deactivate_wifi;

lv_obj_t *ui_wifi2;

lv_obj_t *ui_home_symbol2;

lv_obj_t *ui_Home_label2;

lv_obj_t *ui_no_wifi_image1;

void ui_event_deactivate_button( lv_event_t * e);

lv_obj_t *ui_deactivate_button;

lv_obj_t *ui_deactivate_label;

lv_obj_t *ui_explain_label1;

// CUSTOM VARIABLES

// SCREEN: ui_success_wifi

void ui_success_wifi_screen_init(void);

lv_obj_t *ui_success_wifi;

lv_obj_t *ui_wifi3;

lv_obj_t *ui_home_symbol3;

lv_obj_t *ui_Home_label3;

lv_obj_t *ui_success_image;

void ui_event_next_button( lv_event_t * e);

lv_obj_t *ui_next_button;

lv_obj_t *ui_next_label;

lv_obj_t *ui_explain_label2;

// CUSTOM VARIABLES

// SCREEN: ui_qr_code

void ui_qr_code_screen_init(void);

lv_obj_t *ui_qr_code;

lv_obj_t *ui_wifi4;

lv_obj_t *ui_home_symbol4;

lv_obj_t *ui_Home_label4;

lv_obj_t *ui_qr_image;

lv_obj_t *ui_explain_label3;

// CUSTOM VARIABLES

// SCREEN: ui_user_setup

void ui_user_setup_screen_init(void);

lv_obj_t *ui_user_setup;

lv_obj_t *ui_wifi5;

lv_obj_t *ui_home_symbol5;

lv_obj_t *ui_Home_label5;

lv_obj_t *ui_no_wifi_image2;

void ui_event_next_to_main_page( lv_event_t * e);

lv_obj_t *ui_next_to_main_page;

lv_obj_t *ui_next_label1;

lv_obj_t *ui_hey_label;

lv_obj_t *ui_success_label;

// CUSTOM VARIABLES

// SCREEN: ui_welcome_screen

void ui_welcome_screen_screen_init(void);

void ui_event_welcome_screen( lv_event_t * e);

lv_obj_t *ui_welcome_screen;

lv_obj_t *ui_wifi6;

lv_obj_t *ui_home_symbol6;

lv_obj_t *ui_Home_label6;

lv_obj_t *ui_Image3;

// CUSTOM VARIABLES

// EVENTS

lv_obj_t *ui____initial_actions0;

// IMAGES AND IMAGE SETS

///////////////////// TEST LVGL SETTINGS ////////////////////

#if LV_COLOR_DEPTH != 16

#error "LV_COLOR_DEPTH should be 16bit to match SquareLine Studio's settings"

#endif

#if LV_COLOR_16_SWAP !=0

#error "LV_COLOR_16_SWAP should be 0 to match SquareLine Studio's settings"

#endif

///////////////////// ANIMATIONS ////////////////////

///////////////////// FUNCTIONS ////////////////////

void ui_event_resetbutton( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

tare_weight( e );

}

}

void ui_event_addfriendsbutton( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

_ui_screen_change( &ui_casual_friends, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_casual_friends_screen_init);

}

}

void ui_event_send_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

send_log( e );

}

}

void ui_event_casual_friends( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

plusbutton( e );

}

}

void ui_event_Cancel_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

_ui_screen_change( &ui_Mainscreenwithoutfriens, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_Mainscreenwithoutfriens_screen_init);

}

}

void ui_event_Done_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

done_button( e );

}

}

void ui_event_plus_buttun( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

plusbutton( e );

}

}

void ui_event_minus_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

minusbutton( e );

}

}

void ui_event_activate_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

_ui_screen_change( &ui_deactivate_wifi, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_deactivate_wifi_screen_init);

}

if ( event_code == LV_EVENT_RELEASED) {

activateWifi( e );

}

}

void ui_event_deactivate_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

_ui_screen_change( &ui_activate_wifi, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_activate_wifi_screen_init);

}

if ( event_code == LV_EVENT_RELEASED) {

DeactivateWifi( e );

}

}

void ui_event_next_button( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

_ui_screen_change( &ui_qr_code, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_qr_code_screen_init);

}

}

void ui_event_next_to_main_page( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_RELEASED) {

_ui_screen_change( &ui_Mainscreenwithoutfriens, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_Mainscreenwithoutfriens_screen_init);

}

}

void ui_event_welcome_screen( lv_event_t * e) {

lv_event_code_t event_code = lv_event_get_code(e);

if ( event_code == LV_EVENT_SCREEN_LOADED) {

_ui_screen_change( &ui_activate_wifi, LV_SCR_LOAD_ANIM_FADE_ON, 500, 3000, &ui_activate_wifi_screen_init);

}

}

///////////////////// SCREENS ////////////////////

void ui_init( void )

{

lv_disp_t *dispp = lv_disp_get_default();

lv_theme_t *theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), false, LV_FONT_DEFAULT);

lv_disp_set_theme(dispp, theme);

ui_Mainscreenwithoutfriens_screen_init();

ui_casual_friends_screen_init();

ui_activate_wifi_screen_init();

ui_deactivate_wifi_screen_init();

ui_success_wifi_screen_init();

ui_qr_code_screen_init();

ui_user_setup_screen_init();

ui_welcome_screen_screen_init();

ui____initial_actions0 = lv_obj_create(NULL);

lv_disp_load_scr( ui_welcome_screen);

}

ui_events.c:


// This file was generated by SquareLine Studio
// SquareLine Studio version: SquareLine Studio 1.5.1
// LVGL version: 8.3.11
// Project name: SquareLine_Project

#include "ui.h"


extern void AP_on(lv_event_t * e);
extern void AP_off(lv_event_t * e);

extern void reset_weight(lv_event_t * e);


void tare_weight(lv_event_t * e)
{
  // Your code here
  reset_weight(e);
}

void send_log(lv_event_t * e)
{
  // Your code here
}

void plusbutton(lv_event_t * e)
{
  // Your code here
}

void done_button(lv_event_t * e)
{
  // Your code here
}

void minusbutton(lv_event_t * e)
{
  // Your code here
}

void activateWifi(lv_event_t * e)
{
    // Delay AP start to allow screen to finish rendering
    lv_timer_t *t = lv_timer_create(AP_on, 1500, NULL);
    lv_timer_set_repeat_count(t, 1);
}

void DeactivateWifi(lv_event_t * e)
{
    // Delay AP stop to allow screen to finish rendering
    lv_timer_t *t = lv_timer_create(AP_off, 1500, NULL);
    lv_timer_set_repeat_count(t, 1);
}




### Others
- **SquareLine Studio version:** latest
- **Operating system:** Mac OS
- **Target hardware:** ESP32 DA crowPanel 2.4 inch touch screen

Hi, I’ve analyzed your code and can see what’s happening with the white screen issue after connecting to the AP. The problem is with how you’re handling the screen transition in your loop.

The issue is in your loop() function where you detect device connections:

if (WiFi.getMode() == WIFI_AP) {
    int numStations = WiFi.softAPgetStationNum();
    if (numStations > 0 && !phoneConnected) {
        phoneConnected = true;
        Serial.println("[INFO] Phone connected. Switching to QR code screen.");

        if (!qrScreenCreated) {
            ui_qr_code_screen_init();  // Create the QR code screen only once
            qrScreenCreated = true;
        }
        lv_scr_load(ui_qr_code);
        //lv_obj_invalidate(ui_qr_code);
    }
}

There are a few problems here:

  1. You’re directly calling lv_scr_load() outside of the main LVGL task which can cause concurrency issues
  2. You’re not using the SquareLine Studio’s built-in screen change function _ui_screen_change()
  3. The screen rendering might be interrupted by other operations in the loop

Try modifying your approach like this:

if (WiFi.getMode() == WIFI_AP) {
    int numStations = WiFi.softAPgetStationNum();
    if (numStations > 0 && !phoneConnected) {
        phoneConnected = true;
        Serial.println("[INFO] Phone connected. Switching to QR code screen.");
        
        // Use a timer to delay the screen change slightly
        static lv_timer_t* screen_change_timer = NULL;
        if (screen_change_timer == NULL) {
            screen_change_timer = lv_timer_create([](lv_timer_t* timer) {
                _ui_screen_change(&ui_qr_code, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_qr_code_screen_init);
                lv_timer_del(timer);
            }, 100, NULL);
        }
    }
}

This way, the screen change happens within the LVGL context and has a better chance of succeeding without crashing.

Also, I’d suggest simplifying your main loop to ensure LVGL gets enough processing time. Move the WiFi connection check to a timer callback as well.

Let me know if this works for you, and feel free to ask if you need any additional help!