Change Screens using Buttons

Description

I am writing an application that is using at least three screens to perform actions and display data.

I have searched the internet and I have found many people asking what is the correct way to do this, but I have not come across an example that works for me.

At present, every time I try to change screens, the ESP32 restarts with:
“Guru Meditation Error: Core 1 panic’ed (InstrFetchProhibited). Exception was unhandled.”

What MCU/Processor/Board and compiler are you using?

Espressive ESP32-S3-WROOM-1

What LVGL version are you using?

Currently using 8.3.0 - I have also tried the latest

What do you want to achieve?

I am looking to put together an example that I can use and share with others that are having the same problem as me.

What have you tried so far?

Too many examples to mention here…

Code to reproduce

Add a code snippet which can run in the simulator. It should contain only the relevant code that compiles without errors when separated from your main code base.

The code block(s) should be formatted like:

 //******************************* MY CODE *******************************************
    //screen1 = lv_scr_act();
    screen1 = lv_obj_create(NULL);
    lv_obj_t * button1 = lv_btn_create(screen1);
    lv_obj_add_event_cb(button1, button_event_cb, LV_EVENT_CLICKED, NULL);
    lv_obj_set_size(button1, 170, 80);
    lv_obj_set_pos(button1, 32, 100);
    lv_obj_t * label1 = lv_label_create(button1);
    lv_label_set_text(label1, "Button 1");

    lv_obj_t * button2 = lv_btn_create(screen1);
    lv_obj_add_event_cb(button2, button_event_cb, LV_EVENT_CLICKED, NULL);
    lv_obj_set_size(button2, 170, 80);
    lv_obj_set_pos(button2, 249, 100);
    lv_obj_t * label2 = lv_label_create(button2);
    lv_label_set_text(label2, "Button 2");

    screen2 = lv_obj_create(NULL);
    //lv_scr_load(screen2);

    lv_obj_t * button3 = lv_btn_create(screen2);
    lv_obj_add_event_cb(button3, button_event_cb, LV_EVENT_CLICKED, NULL);
    lv_obj_set_size(button3, 170, 80);
    lv_obj_set_pos(button3, 249, 100);
    lv_obj_t * label3 = lv_label_create(button2);
    lv_label_set_text(label3, "Button 3");

    screen3 = lv_obj_create(NULL);
    //lv_scr_load(screen3);

    lv_scr_load(screen1);
    //lv_scr_load(screen2);
    // lv_scr_load(screen3);

    printf("Setup done\n");
  }
}

void loop()
{
  lv_timer_handler(); /* let the GUI do its work */
  delay(5);

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    //espnow_senddata();
  }

}

void button_event_cb(lv_event_t *event){
  //lv_obj_t *screen1;
  lv_obj_t *screen2;
  //lv_obj_t *screen3;

  lv_obj_t *btn = lv_event_get_target(event);
  lv_obj_t * label = lv_obj_get_child(btn, 0);
  const char * text = lv_label_get_text(label);
  printf ("Button_Touched: %s \n", text);

  if(strcmp(text, "Button 2") == 0) {
    printf ("Goto Screen: %s \n", text);
    //lv_scr_load(scn2);
    //lv_obj_clean(lv_scr_act());
    //lv_scr_load(screen2);

    //lv_scr_load(lv_scr_act());
    printf ("Clean Screen1:\n");
    lv_obj_clean(screen1);
    printf ("Delete Screen1:\n");
    lv_obj_del(screen1);

    //printf ("Clean Screen2:\n");
    //lv_obj_clean(screen2);
    //printf ("Delete Screen2:\n");
    //lv_obj_del(screen2);

    printf ("Load Screen3:\n");
    lv_scr_load(screen3);
    //Comment
  }

}

// void button2_event_cb(lv_event_t *event)
// {
//     // if(event == LV_EVENT_CLICKED) {
//     lv_scr_load(lv_scr_act());
//     // }
// }
 21224][E][Wire.cpp:�ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3808,len:0x44c
load:0x403c9700,len:0xbe4
load:0x403cc700,len:0x2a38
entry 0x403c98d4
[   129][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
[   701][I][esp32-hal-i2c.c:75] i2cInit(): Initialising I2C Master: sda=19 scl=20 freq=100000
[   701][W][Wire.cpp:301] begin(): Bus already started in Master Mode.
[   704][E][esp32-hal-gpio.c:102] __pinMode(): Invalid pin selected
E (582) gpio: gpio_set_level(226): GPIO output gpio_num error
E (597) gpio: gpio_set_level(226): GPIO output gpio_num error
E (603) gpio: gpio_set_level(226): GPIO output gpio_num error
[   781][E][esp32-hal-gpio.c:102] __pinMode(): Invalid pin selected
Setup done
Button_Touched: Button 1 
Button_Touched: Button 1 
Button_Touched: Button 1 
Button_Touched: Button 2 
Goto Screen: Button 2
Clean Screen1:
Delete Screen1:
Load Screen3:
Guru Meditation Error: Core  1 panic'ed (InstrFetchProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x00000205  PS      : 0x00060030  A0      : 0x82002cb7  A1      : 0x3fceba30
A2      : 0x00000205  A3      : 0x3fceba74  A4      : 0x3fc973a8  A5      : 0x00000000  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x8204a9ad  A9      : 0x3fceba00
A10     : 0x3fc973a8  A11     : 0x3fceba74  A12     : 0x3fca4720  A13     : 0x3c0508e7  
A14     : 0x3c050831  A15     : 0x3c050841  SAR     : 0x0000000a  EXCCAUSE: 0x00000014
EXCVADDR: 0x00000204  LBEG    : 0x400556d5  LEND    : 0x400556e5  LCOUNT  : 0xfffffff0  


Backtrace: 0x00000202:0x3fceba30 0x42002cb4:0x3fceba50 0x42002e5e:0x3fceba70 0x420091de:0x3fcebab0 0x42009739:0x3fcebae0 0x42009bff:0x3fcebb00 0x42006429:0x3fcebb20 0x4200646d:0x3fcebb50 0x420029ac:0x3fcebb70 0x42002c65:0x3fcebc30 0x420024ae:0x3fcebc50 0x42002e02:0x3fcebc70 0x42002e5e:0x3fcebc90 0x4200344e:0x3fcebcd0 0x42003b04:0x3fcebd00 0x42019000:0x3fcebd50 0x420026bf:0x3fcebd80 0x4202b251:0x3fcebda0

  #0  0x00000202:0x3fceba30 in ?? ??:0
  #1  0x42002cb4:0x3fceba50 in event_send_core at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_event.c:458
  #2  0x42002e5e:0x3fceba70 in lv_event_send at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_event.c:75
  #3  0x420091de:0x3fcebab0 in lv_obj_refresh_style at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_obj_style.c:187
      (inlined by) lv_obj_refresh_style at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_obj_style.c:167
  #4  0x42009739:0x3fcebae0 in lv_obj_set_local_style_prop at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_obj_style.c:275
  #5  0x42009bff:0x3fcebb00 in lv_obj_set_style_x at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_obj_style_gen.c:56
  #6  0x42006429:0x3fcebb20 in lv_obj_set_x at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_obj_pos.c:62
  #7  0x4200646d:0x3fcebb50 in lv_obj_set_pos at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_obj_pos.c:48
  #8  0x420029ac:0x3fcebb70 in lv_scr_load_anim at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_disp.c:232
  #9  0x42002c65:0x3fcebc30 in lv_disp_load_scr at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_disp.c:84
  #10 0x420024ae:0x3fcebc50 in button_event_cb(_lv_event_t*) at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_disp.h:207
      (inlined by) button_event_cb(_lv_event_t*) at src/main.cpp:256
  #11 0x42002e02:0x3fcebc70 in event_send_core at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_event.c:467
  #12 0x42002e5e:0x3fcebc90 in lv_event_send at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_event.c:75
  #13 0x4200344e:0x3fcebcd0 in indev_proc_release at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_indev.c:980
  #14 0x42003b04:0x3fcebd00 in indev_pointer_proc at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_indev.c:384
      (inlined by) lv_indev_read_timer_cb at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/core/lv_indev.c:101
  #15 0x42019000:0x3fcebd50 in lv_timer_exec at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/misc/lv_timer.c:313
      (inlined by) lv_timer_handler at .pio/libdeps/esp32-s3-Sunton_800x480/lvgl/src/misc/lv_timer.c:109
  #16 0x420026bf:0x3fcebd80 in loop() at src/main.cpp:217
  #17 0x4202b251:0x3fcebda0 in loopTask(void*) at C:/Users/dpunt/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:50




ELF file SHA256: 4db1e7f78ea52109

Rebooting...

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.

Maybe you misunderstand screen elements and how lvgl work. Is bad idea have button on screen 1 and you try in touch callback delete all screen ( is still active! )
Your memory must crash simply explain you drive over bridge and bridge disapear.

Try create GUI in squareline and learn how code is generated. Too in squareline you can simulate before load into board…

Hi @Marian_M

Thanks for your reply.

I agree that I don’t fully understand LVGL screens, but I do understand that I need to switch to a new screen, before deleting the existing / in-use one. As you have referred, I did learn this from using Squareline Studio and watching the videos.

Find below a better example of what I am trying to achieve in my callback procedure.

void button_event_cb(lv_event_t *event){

  lv_obj_t *btn = lv_event_get_target(event);
  lv_obj_t * label = lv_obj_get_child(btn, 0);
  const char * text = lv_label_get_text(label);
  printf ("Button_Touched: %s \n", text);

  if(strcmp(text, "Goto_Screen2") == 0) {
    printf ("Goto Screen: %s \n", text);

    printf ("Load Screen2:\n");
    lv_scr_load(screen2);
    printf ("Clean Screen1:\n");
    lv_obj_clean(screen1);
    printf ("Delete Screen1:\n");
    lv_obj_del(screen1);

  }
  if(strcmp(text, "Goto_Screen3") == 0) {
    printf ("Goto Screen: %s \n", text);

    printf ("Load Screen3:\n");
    lv_scr_load(screen3);
    printf ("Clean Screen2:\n");
    lv_obj_clean(screen2);
    printf ("Delete Screen2:\n");
    lv_obj_del(screen2);

  }
  if(strcmp(text, "Goto_Screen1") == 0) {
    printf ("Goto Screen: %s \n", text);

    printf ("Load Screen1:\n");
    lv_scr_load(screen1);
    printf ("Clean Screen3:\n");
    lv_obj_clean(screen3);
    printf ("Delete Screen3:\n");
    lv_obj_del(screen3);

  }
  else{
    return;
  }

}

However, using this example I still cannot switch back to Screen1.

Setup done
Button_Touched: Test
Button_Touched: Test
Button_Touched: Goto_Screen2
Goto Screen: Goto_Screen2
Load Screen2:
Clean Screen1:
Delete Screen1:
Button_Touched: Goto_Screen3
Goto Screen: Goto_Screen3
Load Screen3:
Clean Screen2:
Delete Screen2:
Button_Touched: Goto_Screen1
Goto Screen: Goto_Screen1
Load Screen1:
Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception was unhandled.

If I delete a screen do I need to recreate it?

Or, any idea what could be happening here?

jump into implementing this del func and see why you cant use deleted obj repeatly.

I am looking for some help here???

I posted something that works.

If this is not the correct way, then what is the correct way?

It should be simple, just provide me / US with a few lines of code.

Simply your ask isnt about LVGL , but about ignore read docu, then reply is …
Your code is ok only remove CLEAN and DEL lines. Why read docu.

So I gather that you don’t know the correct way or you would share it with us.

I have been a computer programmer for more than 40 years. I know a bit about programming with very little memory.

My question is specifically about LVGL.

Ok seems you 40 years dont read docu , then try now

then as you write when you clean and delete screen you require create it before load. As simple as possible.

And correct way is not delete repeatly used objects in any system. Only effective is it where real memory trouble exist.

Firstly, thanks for providing me with a little bit of documentation. Now we are getting somewhere.

And yes, I have read this document several times. I also read where you have to clean the screen. Hence why I was asking what is the correct way?

In other programming languages you can create an object and then load and unload (swap) that object in and out when you require it.

So, I asked the question specifically about LVGL - thanks for providing an answer!

You stated “Your code is ok only remove CLEAN and DEL lines
However, if I remove lv_obj_del(obj) my EPS restarts.

Following is my latest callback code which I am happy to share with everybody on this forum. It works, I have tested it by pressing the buttons over 500 times.

void button_event_cb(lv_event_t *event){

  lv_obj_t *btn = lv_event_get_target(event);
  lv_obj_t * label = lv_obj_get_child(btn, 0);
  const char * text = lv_label_get_text(label);
  printf ("Button_Touched: %s \n", text);
  printf("[APP] Minimum memory: %s bytes\n", String(esp_get_minimum_free_heap_size()));

  if(strcmp(text, "Goto_Screen2") == 0) {
    printf ("Goto Screen: %s \n", text);

    printf ("Load Screen2:\n");
    Create_Screen2();
    lv_scr_load(screen2);

    printf("[APP] Free memory: %s bytes\n", String(esp_get_free_heap_size()));
    printf ("Delete Screen1:\n");
    lv_obj_del(screen1);
    printf("[APP] Free memory: %s bytes\n", String(esp_get_free_heap_size()));

  }
  if(strcmp(text, "Goto_Screen3") == 0) {
    printf ("Goto Screen: %s \n", text);

    printf ("Load Screen3:\n");
    Create_Screen3();
    lv_scr_load(screen3);

    printf("[APP] Free memory: %s bytes\n", String(esp_get_free_heap_size()));
    printf ("Delete Screen2:\n");
    lv_obj_del(screen2);
    printf("[APP] Free memory: %s bytes\n", String(esp_get_free_heap_size()));

  }
  if(strcmp(text, "Goto_Screen1") == 0) {
    printf ("Goto Screen: %s \n", text);

    printf ("Create Screen1:\n");
    Create_Screen1();
    lv_scr_load(screen1);

    printf("[APP] Free memory: %s bytes\n", String(esp_get_free_heap_size()));
    printf ("Delete Screen3:\n");
    lv_obj_del(screen3);
    printf("[APP] Free memory: %s bytes\n", String(esp_get_free_heap_size()));

  }
  else{
    return;
  }

}

Yes your code save memory, but waste energy and MCU power for recreate … CO2

And LVGL is cleanly defined as C library , then write about other lang is waste time.

Too when you animate somethink on screens is complicated delete it and manage all. Too sometimes your actual delete code crash because lv is timed handler code and load screenX exactly dont unload previous screen immediately, then del call is better place into screen unloaded callback.

And Squareline have for this temporary screen settings.
image

Sorry but I don’t understand how your last reply adds any value to the conversation. But, it would appear that English is your second language so I may have lost something in the translation.

It may be simpler if you modified my code to show exactly the way it should be done.

I have been looking at - lv_obj_del_async(obj)

Perhaps this could be used in this situation.

I have used the SquareLine Studio GUI, but I much prefer to write the code myself. That way, I better understand what is happening.

You sk right way i only try direct you
in create screen

lv_obj_add_event_cb(ui_Screen3, scr_unloaded_delete_cb, LV_EVENT_SCREEN_UNLOADED, &ui_Screen3);

void scr_unloaded_delete_cb(lv_event_t * e)
{
   lv_obj_t ** var = lv_event_get_user_data(e);
   lv_obj_del(*var);
   (*var) = NULL;
}

You can try using Fragment — LVGL documentation to manage the lifecycle of the page.