ESP32 - cant change object properties

Description

I have posted and deleted bugs over the last few days because I thought there was something else i could try.

I am trying to something really simple but cannot seem to do it and now I think it might be a bug.

I am showing a simplified example that allows me to illustrate the issue.

In the example:

  1. I take a serial input being sent to the esp32, which alternates between a single character and is sent each second.
  2. I create three led objects in my setup and then change their appearance based on the serial result.

Problem:

when I execute the code described as above the ESP32 either stops responding in the case of the LED and when I have used it on other examples where I setup the object first in setup and then change its background property the ESP32 crashed with " Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception was unhandled".

The only way I can get it to work is how it is shown in the example, where you create the led each time, but I know that you don’t have to create the objects each time and lo and behold it freezes after about 20 updates.

The work I have done for the last week has been on the lv_printer_example() and I have simplified it to this code to reproduce. I hope its not just the esp32 that is the issue :(.

sorry if I am doing something silly, but I really want to keep using this platform for my dev work but cant get past this basic hurdle.

If my implementation is wrong then please show me an example that would flash the alternate LEDs by updating the object state after it has been created.

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

ESP32-WROOM-32D connected via SPI bus to ILI9488 Screen

What LVGL version are you using?

7.8

What do you want to achieve?

What have you tried so far?

I have tried changing:

set in lv_conf.h

> #define LV_USE_ASSERT_MEM_INTEGRITY       1
> #define LV_USE_ASSERT_OBJ       1
> #define LV_USE_ASSERT_STYLE     1

Tried creating a task that scans the change and updates but this also crashes with same result.

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:

#include <lvgl.h>
#include <TFT_eSPI.h>

#include <SPI.h>
#include <Ticker.h>



#define RXD2 12
#define TXD2 14

int counter = 0;
static String LoRaData;

static lv_obj_t * led1;
static lv_obj_t * led2;
static lv_obj_t * led3;


#define screenWidth 480
#define screenHeight 320
#define LVGL_TICK_PERIOD 20

TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
Ticker   lvgl_tick;             /* timer for lvgl */


static lv_obj_t* add_title(const char* txt);



#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * fn_name, const char * dsc)
{

  Serial.printf("%s@%d->%s\r\n", file, line, dsc);
  Serial.flush();
}
#endif

/* Display flushing */
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);

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

  lv_disp_flush_ready(disp);
}

/*Read the touchpad*/
bool my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
  uint16_t touchX, touchY;

  bool touched = tft.getTouch(&touchX, &touchY, 600);

  if (!touched)
  {
    data->state = LV_INDEV_STATE_REL;
    return false;
  }
  else
  {
    data->state = LV_INDEV_STATE_PR;
  }

  if (touchX > screenWidth || touchY > screenHeight)
  {
    Serial.println("Y or y outside of expected parameters..");
    Serial.print("y:");
    Serial.print(touchX);
    Serial.print(" x:");
    Serial.print(touchY);
  }
  else
  {
    /*Set the coordinates*/
    if (3 == tft.getRotation()) {
      //Shift coordinates
      data->point.x = 480 - touchX;
      data->point.y = 320 - touchY;
    } else if (1 == tft.getRotation()) {
      data->point.x = touchX;
      data->point.y = touchY;
    }

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

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

  return false; /*Return `false` because we are not buffering and no more data to read*/




}

void lv_tick_handler() {
  lv_tick_inc(LVGL_TICK_PERIOD);
}


void setup()
{
  Serial.begin(115200); /* prepare for possible serial debug */
  Serial1.begin(115200, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Serial Txd is on pin: "+String(TX));
  Serial.println("Serial Rxd is on pin: "+String(RX));

      pinMode(13, OUTPUT);
      digitalWrite(13, HIGH);

  lv_init();

#if LV_USE_LOG != 0
  lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif

  tft.begin(); /* TFT init */
  tft.setRotation(1); /* Landscape orientation */

  // uint16_t calData[5] = { 305, 3542, 245, 3529, 3  };
  uint16_t calData[5] = { 270, 3639, 250, 3556, 7  };
  tft.setTouch(calData);

  lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

  /*Initialize the display*/
  lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = 480;
  disp_drv.ver_res = 320;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.buffer = &disp_buf;
  lv_disp_drv_register(&disp_drv);

  /*Initialize the (dummy) input device driver*/
  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);


  lvgl_tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);


}


}

void loop()
{

// Serial.println(char(Serial1.read()));


      lv_task_handler(); /* let the GUI do its work */
      delay(5);




      while (Serial1.available()) {
        // Serial.print(char(Serial1.read()));
        LoRaData = (char(Serial1.read()));

        Serial.println(LoRaData);


        if(LoRaData=="L"){

              lv_obj_t * led1  = lv_led_create(lv_scr_act(), NULL);
              lv_obj_align(led1, NULL, LV_ALIGN_CENTER, -80, 0);

              lv_obj_t * led2  = lv_led_create(lv_scr_act(), led1);
              lv_obj_align(led2, NULL, LV_ALIGN_CENTER, 0, 0);

              lv_obj_t * led3  = lv_led_create(lv_scr_act(), led1);
              lv_obj_align(led3, NULL, LV_ALIGN_CENTER, 80, 0);


              lv_led_off(led1);

              lv_led_set_bright(led2, 190);

              lv_led_on(led3);

              yield();
              delay(5);
            }
        else if(LoRaData=="O"){

              lv_obj_t * led1  = lv_led_create(lv_scr_act(), NULL);
              lv_obj_align(led1, NULL, LV_ALIGN_CENTER, -80, 0);

              lv_obj_t * led2  = lv_led_create(lv_scr_act(), led1);
              lv_obj_align(led2, NULL, LV_ALIGN_CENTER, 0, 0);

              lv_obj_t * led3  = lv_led_create(lv_scr_act(), led1);
              lv_obj_align(led3, NULL, LV_ALIGN_CENTER, 80, 0);

              lv_led_on(led1);

              lv_led_set_bright(led2, 190);

              lv_led_off(led3);

                yield();
              delay(5);


            }
            else{



              Serial.println("CONDISTION NOT MET");
            }




    }


}

Screenshot and/or video

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

Creating the LEDs multiple times is definitely not the way to go here. It would be most ideal if you could use a debugger to find where the crash is happening when you don’t create them multiple times. I suspect this is memory corruption or something similar on your platform.

Hi,

Thanks for your response.

I am beginning to think that it might not be a crash. I set the FPS setting on and I can see that the CPU is hitting 100%. what would be the right way to setup the leds once and the update in the loop so that I know I am not doing it wrong"?

Create them in setup then change them in loop. If it crashes, send the modified code and I’ll see if anything obvious is wrong.

So here is a completely different example with a gauge and it works when I create the gauge in the loop for a few mins but not at all when created in setup. I am not getting a crash but a freeze.

#include <lvgl.h>
#include <TFT_eSPI.h>

#include <SPI.h>
#include <Ticker.h>


static lv_obj_t * gauge;
static lv_obj_t * label;

static bool stateChange=false;

#define screenWidth 480
#define screenHeight 320
#define LVGL_TICK_PERIOD 20

TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
Ticker   lvgl_tick;             /* timer for lvgl */

long  triggerInterval = 0;

static lv_obj_t* add_title(const char* txt);

// ----



#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * fn_name, const char * dsc)
{

  Serial.printf("%s@%d->%s\r\n", file, line, dsc);
  Serial.flush();
}
#endif

/* Display flushing */
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);

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

  lv_disp_flush_ready(disp);
}

/*Read the touchpad*/
bool my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
  uint16_t touchX, touchY;

  bool touched = tft.getTouch(&touchX, &touchY, 600);

  if (!touched)
  {
    data->state = LV_INDEV_STATE_REL;
    return false;
  }
  else
  {
    data->state = LV_INDEV_STATE_PR;
  }

  if (touchX > screenWidth || touchY > screenHeight)
  {
    Serial.println("Y or y outside of expected parameters..");
    Serial.print("y:");
    Serial.print(touchX);
    Serial.print(" x:");
    Serial.print(touchY);
  }
  else
  {
    /*Set the coordinates*/
    if (3 == tft.getRotation()) {
      //Shift coordinates
      data->point.x = 480 - touchX;
      data->point.y = 320 - touchY;
    } else if (1 == tft.getRotation()) {
      data->point.x = touchX;
      data->point.y = touchY;
    }

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

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

  return false; /*Return `false` because we are not buffering and no more data to read*/




}

void lv_tick_handler() {
  lv_tick_inc(LVGL_TICK_PERIOD);
}


void setup()
{
  Serial.begin(115200); /* prepare for possible serial debug */
  Serial1.begin(115200, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Serial Txd is on pin: "+String(TX));
  Serial.println("Serial Rxd is on pin: "+String(RX));

      pinMode(13, OUTPUT);
      digitalWrite(13, HIGH);

  lv_init();

#if LV_USE_LOG != 0
  lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif

  tft.begin(); /* TFT init */
  tft.setRotation(1); /* Landscape orientation */

  // uint16_t calData[5] = { 305, 3542, 245, 3529, 3  };
  uint16_t calData[5] = { 270, 3639, 250, 3556, 7  };
  tft.setTouch(calData);

  lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

  /*Initialize the display*/
  lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  disp_drv.hor_res = 480;
  disp_drv.ver_res = 320;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.buffer = &disp_buf;
  lv_disp_drv_register(&disp_drv);

  /*Initialize the (dummy) input device driver*/
  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);


  lvgl_tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);



// lv_main_screen();

lv_obj_t* gauge = lv_gauge_create(lv_scr_act(), NULL);
lv_obj_t* label = lv_label_create(gauge, NULL);
lv_obj_set_pos(gauge, 20, 20);
lv_obj_set_size(gauge, 250, 250);
lv_gauge_set_range(gauge, 0, 1000);

lv_label_set_text(label, "POT");
lv_obj_align(label, gauge, LV_ALIGN_CENTER, 0, 50);

lv_task_t* task = lv_task_create(task_cb, 1000, LV_TASK_PRIO_LOW, NULL);




}

void task_cb(lv_task_t * task)
{
  // lv_task_t* task = lv_task_create(task_cb, 100, LV_TASK_PRIO_MID, NULL);

  if(stateChange){
    Serial.println(triggerInterval);

    lv_gauge_set_value(gauge, NULL, triggerInterval);

stateChange = false;
}
}


}




}

void loop()
{



      lv_task_handler(); /* let the GUI do its work */
      delay(5);




      while (Serial1.available()) {
        LoRaData = (char(Serial1.read()));

        Serial.println(LoRaData);



        if(LoRaData=="L"){
              stateChange = true;
              triggerInterval = 100;
            }
        else if(LoRaData=="O"){
              stateChange = true;

              triggerInterval = 900;



            }



    }



}
}

it seems like there is a problem in sending individual update to properties outside of the function where the main object has been created. is there a setting somewhere which might take care of this?

Might help if you don’t redeclare the variable inside setup, thus shadowing the global variable outside of it. :wink:

Change it to this:

/* note no lv_obj_t * declaration */
gauge = lv_gauge_create(lv_scr_act(), NULL);
label = lv_label_create(gauge, NULL);
1 Like

@embeddedt You are a Prince amongst men!! Thank you so much! Next time I won’t mess around for a week and just post the question!

one more opinion, if I may. I am designing this device to be used commercially. I have the choice of using the lvgl esp-idf version ep32 port https://github.com/lvgl/lv_port_esp32 or this arduino version.

The esp-idf version does not support parallel connection for the ili9488, but the arduino version does support.

which is the best choice for stability and performance?

I think @Carlos_Diaz or @Pablo2048 are more qualified to answer that question than I am.

1 Like

The difference between lv_port_esp32 and "this" arduino version is just the presence of TFTeSPI library as an (ultra) fast low level driver. I’m not using lv_port_esp32 so its up to you to compare the performance of low level TFT driver from lv_port_esp32 and TFTeSPI.

1 Like

Hi @J45p41

As @Pablo2048 said, the drivers on the Arduino version are using TFTeSPI, while the drivers on the lv_port_esp32 were contributed by the users.
And the lv_port_esp32 is using the ESP-IDF framework directly, so you can configure LVGL and ESP32 peripherals and modules using the menuconfig interface.

1 Like

Thank you both for the insights. I have a setup that does not require any external peripherals besides Lora- RFM95W. So I am thinking that it’s better to use the parallel interface so that Lora can have the spi bus to itself, I have seen issues with sharing the spi bus between Lora and the ili9488 driver see

LoRa fails to start running dual core ESP32 with Bodmers TFT_eSPI library · Issue #290 · sandeepmistry/arduino-LoRa · GitHub

So based on the fact that boomers tft library is more likely to be more stable and supports parallel- would I be better off sticking to arduino?

I would stick with Arduino for a while because I don’t have any parallel display to add support for it in lv_port_esp32 repo. If in the future, you would like to contribute parallel support on lv_port_esp32 that would be great!