Lv_draw_label Exception in ESP32

Description

I have the next exception after 30 or 60 minutes at run the program, I use one task for update 3 labels with sensor data. This are the exception:

Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400db4fb PS : 0x00060630 A0 : 0x800ecbe0 A1 : 0x3ffd33a0
A2 : 0x000000ff A3 : 0x3ffd3560 A4 : 0x3ffd3568 A5 : 0x00000000
A6 : 0x00000000 A7 : 0x00000175 A8 : 0x0000ffff A9 : 0x0000ffff
A10 : 0x3ffbdc44 A11 : 0x00000000 A12 : 0x0000808e A13 : 0x0000808e
A14 : 0x00000080 A15 : 0x3ffc4294 SAR : 0x00000001 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x4015ffa4 LEND : 0x4015ffae LCOUNT : 0x00000000

ELF file SHA256: 0000000000000000

Backtrace: 0x400db4fb:0x3ffd33a0 0x400ecbdd:0x3ffd3530 0x400d8922:0x3ffd3600 0x400d898f:0x3ffd3650 0x400d89cc:0x3ffd36a0 0x400d8ba1:0x3ffd36c0 0x400d8fd6:0x3ffd3750 0x400e2feb:0x3ffd37a0 0x400e30d1:0x3ffd37c0 0x400d26ef:0x3ffd37e0 0x400f96c1:0x3ffd3800 0x4008964a:0x3ffd3820

Rebooting…
ets Jun 8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10900
load:0x40080400,len:6388
entry 0x400806b4

And this is the output in ESP exception decoder:

Which can be my problem? Thanks in advance.

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

ESP32 NodeMCU with Arduino IDE and ili9341 display

What do you expect?

Run the program without exception.

Code to reproduce

Add a code snippet to reproduce the issue in the simulator. It should contain only the relevant code which can be compiled. Bug reports without code snippets or with erroneous code snippets will not be reviewed.

Use the ```c and ``` tags to format your code:

void readMeasurements(void *pvParameters) {  

   while(1){

    co2m = airSensor.getCO2();
    
    temp = airSensor.getTemperature();
    
    hum = airSensor.getHumidity();

     char co2C[10];
     char tempC[11];
     char humC[10];
    
  
    
      sprintf(co2C, "%i ppm", co2m);
       sprintf(tempC, "%.2f °C", temp);
        sprintf(humC, "%.2f %%", hum);

    lv_label_set_text_fmt(label_co2, co2C);
    lv_label_set_text_fmt(label_temp, tempC);
    lv_label_set_text_fmt(label_hum, humC );
        
    vTaskDelay(2000); 
    }
}

I use other function for make a get to my server that makes an update labels:

void beginWIFITask(void *pvParameters) {


  updateBottomStatus(LV_COLOR_TEAL,"Conectando WIFI: " + ssidName);
    
  unsigned long startingTime = millis();

  WiFi.begin(ssidName.c_str(), password.c_str());
  while (WiFi.status() != WL_CONNECTED && (millis() - startingTime) < timeout)
  {
    vTaskDelay(250);
  }

   if(WiFi.status() != WL_CONNECTED) {
     
    updateBottomStatus(LV_COLOR_RED, "Revisa la contraseña y vuelve a intentarlo otra vez");
    vTaskDelay(2500);
    networkScanner();
    vTaskDelete(NULL);
  }

  int x = 0;
  while(1){
    if(WiFi.status() == WL_CONNECTED){
  
          lv_dropdown_clear_options(ddlist);
          lv_dropdown_add_option(ddlist,"...CONECTADO...",LV_DROPDOWN_POS_LAST);

        updateBottomStatus(LV_COLOR_GREEN, "CONECTADO CORRECTAMENTE, IP: " +  WiFi.localIP().toString());
         delay(100);

         
            if (client.connect(host, 80)){
             
          String url = "/co2GET.php";
          url += "?key=512345j1345jkk4325d9eb43d7";
          url += "&co2=";
          url += co2m;
          url += "&temp=";
          url += temp;
          url += "&hum=";
          url += hum;

    Serial.print("Requesting URL: ");
    Serial.println(url);
      
            // This will send the request to the server
            client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                         "Host: " + host + "\r\n" +
                         "Connection: close\r\n\r\n");


        Serial.println();
        Serial.print("conexión cerrada nº ");
        Serial.println(x++);
      
      updateBottomStatus(LV_COLOR_BLUE, "::Datos enviados correctamente a Sequosentry::");
     
      }

    delay(30000);
    updateBottomStatus(LV_COLOR_GREEN, "::Conectando con Sequosentry::");
   
    
    }else{
           
                 updateBottomStatus(LV_COLOR_RED, "::No se puede conectar con la red, revise la conexion::");
                 delay(30000);
                 Serial.print("INTENTANDO CONECTAR AL WIFI: ");
                 Serial.print(ssidName);
                 Serial.print(" ");
                 Serial.println(password);
                 WiFi.disconnect();
                 WiFi.begin(ssidName.c_str(), password.c_str()); 
               
                
    }
  }
    updateBottomStatus(LV_COLOR_RED, "::Se perdio la conexion con la red WIFI::");
    delay(10000);
    networkScanner();
    vTaskDelete(NULL);
}

And this is the function for update

static void updateBottomStatus(lv_color_t color, String text){
  lv_obj_set_style_local_bg_color(bg_bottom, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT,color);
  lv_label_set_text_fmt(label_status, text.c_str());
  lv_obj_align(label_status, NULL, LV_ALIGN_CENTER, 0, 0);
}

Thanks for all

If these aren’t all on one OS thread you need a mutex.

I’m not sure if i’m doing right, I added this to my code:

//setup
xSemaphore = xSemaphoreCreateMutex();

At the begining of each task that use labels updates I add:

xSemaphoreTake(xSemaphore, portMAX_DELAY);

And in the end:

xSemaphoreGive(xSemaphore);

But I have the same exception, this is the complete code:

 void readMeasurements(void *pvParameters) {  

   while(1){
    
    xSemaphoreTake(xSemaphore, portMAX_DELAY);
    
      co2m = airSensor.getCO2();
      temp = int(airSensor.getTemperature());
      hum = int(airSensor.getHumidity());
  
  
  
      lv_label_set_text_fmt(label_co2,"%i ppm", co2m);
      lv_label_set_text_fmt(label_temp, "%i °C", temp);
      lv_label_set_text_fmt(label_hum, "%i %%", hum);

     xSemaphoreGive(xSemaphore);   
    vTaskDelay(2000); 
    }
}


void beginWIFITask(void *pvParameters) {


  updateBottomStatus(LV_COLOR_TEAL,"Conectando WIFI: " + ssidName);
    
  unsigned long startingTime = millis();

  WiFi.begin(ssidName.c_str(), password.c_str());
  while (WiFi.status() != WL_CONNECTED && (millis() - startingTime) < timeout)
  {
    vTaskDelay(250);
  }

   if(WiFi.status() != WL_CONNECTED) {
    updateBottomStatus(LV_COLOR_RED, "Revisa la contraseña y vuelve a intentarlo otra vez");
    vTaskDelay(2500);
    networkScanner();
    vTaskDelete(NULL);
  }

 
  
  int x = 0;
  int y = 0;
  bool w = true;
  while(w){

        
    if(WiFi.status() == WL_CONNECTED){

        xSemaphoreTake(xSemaphore, portMAX_DELAY);
        lv_dropdown_clear_options(ddlist);
        lv_dropdown_add_option(ddlist,"...CONECTADO...",LV_DROPDOWN_POS_LAST);
        updateBottomStatus(LV_COLOR_GREEN, "CONECTADO CORRECTAMENTE, IP: " +  WiFi.localIP().toString());
        xSemaphoreGive(xSemaphore); 
         delay(100);

         
            if (client.connect(host, 80)){
              
            xSemaphoreTake(xSemaphore, portMAX_DELAY);
          String url = "/co2GET.php";
          url += "?key=5f46845d2564327bd9eb43d7";
          url += "&co2=";
          url += co2m;
          url += "&temp=";
          url += temp;
          url += "&hum=";
          url += hum;

    Serial.print("Requesting URL: ");
    Serial.println(url);
      
            // This will send the request to the server
            client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                         "Host: " + host + "\r\n" +
                         "Connection: close\r\n\r\n");


        Serial.println();
        Serial.print("conexión cerrada nº ");
        Serial.println(x++);
      
      updateBottomStatus(LV_COLOR_BLUE, "::Datos enviados correctamente a Sequosentry::");
     xSemaphoreGive(xSemaphore);   
      }

    delay(30000);
    xSemaphoreTake(xSemaphore, portMAX_DELAY);
    updateBottomStatus(LV_COLOR_GREEN, "::Conectando con Sequosentry::");
    xSemaphoreGive( xSemaphore );  
    
    }else{
                 xSemaphoreTake(xSemaphore, portMAX_DELAY);
                 y++;
                 if(y == 3){
                  w = false;
                  xSemaphoreGive( xSemaphore );  
                 }else{
                 client.stop();
                 updateBottomStatus(LV_COLOR_RED, "::No se puede conectar con la red, revise la conexion::");
                 delay(30000);
                 Serial.print("INTENTANDO CONECTAR AL WIFI: ");
                 Serial.print(ssidName);
                 Serial.print(" ");
                 Serial.println(password);
                 WiFi.disconnect();
                 WiFi.mode(WIFI_STA);
                 WiFi.begin(ssidName.c_str(), password.c_str()); 
                 delay(100);
                 xSemaphoreGive( xSemaphore );  
                 }
     
   
    }
  }
     
                xSemaphoreTake(xSemaphore, portMAX_DELAY);
                updateBottomStatus(LV_COLOR_RED, "::Se perdio la conexion con la red WIFI::");
                delay(10000);
                networkScanner();
                xSemaphoreGive( xSemaphore );  
                vTaskDelete(NULL);
                 
}

Also I tried this what I found in a old publication in the forum:

void loop()
{
xSemaphoreTake(xSemaphore, portMAX_DELAY);
lv_task_handler();
xSemaphoreGive(xSemaphore);
delay(5);
}

But I have the same exception after a while

If the crash is still happening with the same frequency then the problem may not be caused by multithreading (though the mutexes are still necessary). The next thing I would suggest is allowing LVGL to check for heap corruption by enabling LV_USE_ASSERT_MEM_INTEGRITY.

One other thing: there might be a bug in your code (not related to this problem). You are deleting the WiFi task before unlocking the semaphore, meaning that the semaphore may not be unlocked. I am not familiar with FreeRTOS semantics so I don’t know whether deleting a task makes it release all its locks or not, but it’s probably a better and more portable practice to unlock the semaphore before you delete it.

First thanks for your support, I amended my code. I enabled in lv_conf the

#define LV_USE_ASSERT_MEM_INTEGRITY       1

What is supposed to happend now?

Thanks.

Try running the program again and see if it crashes. Hopefully, if you are lucky, you will get more information than just LoadProhibited.

It gives me the same exception with the same information. Only I have this exception if I have enabled the beginWIFITask. Thanks for all

It’s likely that there is somewhere where you are not using a mutex properly then. Unfortunately, it’s hard to find out where without disabling parts of the code and experimenting.

I’m going to do more test. I have separeted the task in two threads and the exception still appears, sometimes in 1 min, 5 min, other in 15-30 min and the maximum time has been 89 mins.

This is my code with the two threads:

 void reads(){
 
  vTaskDelay(500);
  xTaskCreatePinnedToCore(readMeasurements,
                "readMeasurements",
                4096,
                NULL,
                0,
                &ntReadTaskHandler,
                0); 
                               
}

void connectWIFI(){
  if(ssidName == NULL || ssidName.length() <1 || password == NULL || password.length() <1){
    return;
  }
  
  vTaskDelete(ntScanTaskHandler);
  vTaskDelay(500);
  xTaskCreatePinnedToCore(beginWIFITask,
                "BeginWIFITask",
                2048,
                NULL,
                1,
                &ntConnectTaskHandler,
                1);                
}

And I tested it with Serial.println(xPortGetCoreID()); , each task execute in a diferent thread

I can also observe that the label at the bottom sometimes doesn’t draw well but when this happens I don’t have an exception, only the label appears like this, thanks

This could happen for a few reasons:

  • Memory corruption.
  • Something reconfiguring or affecting DMA transfers.
  • CPU cache.

The artifacts look reminiscent of cache issues on STM32 but I don’t know if ESP32 has a cache or not.

There have been issues in the past with LVGL when the two ESP32 cores are sharing data. It was some type of bug with cache synchronization; I don’t recall the details. The workaround was to ensure that all tasks which interact with LVGL APIs were pinned to one core.

Sorry for my late reply, I couldn’t do more tests, this weekend i will be able to do the test. Thanks for your support.

It’s solved using lv_tasks. Thanks