Description
When I call the function lv_obj_clean(ui_Search_Result);
, the ESP32 crashes
What MCU/Processor/Board and compiler are you using?
ESP32 with Arduino IDE
What LVGL version are you using?
8.3.11
What do you want to achieve?
I want to clear everything inside the container ui_Search_Result
while being on core 0 (LVGL runs on core 1)
What have you tried so far?
Using a semaphore, running the function in the same core as LVGL (Both which did not solve the problem) and changing screen before clearing the container (the crash is less frequent but it is anoying to have to change screen and it still crashes with the Chnage Page
Buttons). I have checked all other issues about it and tried all what was suggested but they all didn’t work.
Code to reproduce
The functions which I am using are below. The SearchComponent
function is the one which makes the ESP32 crash.
void createChangePage(lv_obj_t* parent, int totalPages, int currentPage) {
lv_obj_t* ui_Change_Page_Menu = ui_ChangePage_create(parent);
// Dynamically retrieve and assign child objects
lv_obj_t* Previous_Page_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PREVIOUS_PAGE);
lv_obj_t* Page_Number_1_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_1_BUTTON);
lv_obj_t* Page_Number_1_Label = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_1_BUTTON_PAGE_NUMBER_1_LABEL);
lv_obj_t* Page_Number_2_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_2_BUTTON);
lv_obj_t* Page_Number_2_Label = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_2_BUTTON_PAGE_NUMBER_2_LABEL);
lv_obj_t* Page_Number_3_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_3_BUTTON);
lv_obj_t* Page_Number_3_Label = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_3_BUTTON_PAGE_NUMBER_3_LABEL);
lv_obj_t* Page_Number_4_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_4_BUTTON);
lv_obj_t* Page_Number_4_Label = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_4_BUTTON_PAGE_NUMBER_4_LABEL);
lv_obj_t* Page_Number_5_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_5_BUTTON);
lv_obj_t* Page_Number_5_Label = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_PAGE_NUMBERS_PAGE_NUMBER_5_BUTTON_PAGE_NUMBER_5_LABEL);
lv_obj_t* Next_Page_Button = ui_comp_get_child(ui_Change_Page_Menu, UI_COMP_CHANGEPAGE_NEXT_PAGE);
// Calculate the starting page number
int startPage = (currentPage < 3) ? 1 : currentPage - 2;
// Set the text for the page number labels
lv_label_set_text_fmt(Page_Number_1_Label, "%d", startPage);
lv_label_set_text_fmt(Page_Number_2_Label, "%d", startPage + 1);
lv_label_set_text_fmt(Page_Number_3_Label, "%d", startPage + 2);
lv_label_set_text_fmt(Page_Number_4_Label, "%d", startPage + 3);
lv_label_set_text_fmt(Page_Number_5_Label, "%d", startPage + 4);
// Add event callbacks with integer parameters
lv_obj_add_event_cb(Previous_Page_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)(currentPage - 1));
lv_obj_add_event_cb(Page_Number_1_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)startPage);
lv_obj_add_event_cb(Page_Number_2_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)(startPage + 1));
lv_obj_add_event_cb(Page_Number_3_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)(startPage + 2));
lv_obj_add_event_cb(Page_Number_4_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)(startPage + 3));
lv_obj_add_event_cb(Page_Number_5_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)(startPage + 4));
lv_obj_add_event_cb(Next_Page_Button, startSearchComponentTask, LV_EVENT_CLICKED, (void*)(currentPage + 1));
// Disable buttons if they are out of range
if (startPage > totalPages) lv_obj_add_flag(Page_Number_1_Button, LV_OBJ_FLAG_HIDDEN);
if (startPage + 1 > totalPages) lv_obj_add_flag(Page_Number_2_Button, LV_OBJ_FLAG_HIDDEN);
if (startPage + 2 > totalPages) lv_obj_add_flag(Page_Number_3_Button, LV_OBJ_FLAG_HIDDEN);
if (startPage + 3 > totalPages) lv_obj_add_flag(Page_Number_4_Button, LV_OBJ_FLAG_HIDDEN);
if (startPage + 4 > totalPages) lv_obj_add_flag(Page_Number_5_Button, LV_OBJ_FLAG_HIDDEN);
}
void SearchComponent(void* parameters) {
// static int page = 1;
int page = (int)parameters; // Cast back to int
if (page <= 0) {
page = 1;
}
const char* SearchText = lv_textarea_get_text(ui_TextArea1);
String SearchTextString = String(SearchText);
SearchTextString.replace(" ", "+");
http.begin("https://theyoungmaker.ddns.net/PartSense/api/SearchComponents.php?keyword=" + SearchTextString + "&resultperpage=" + MAX_COMPONENTS + "&page=" + page);
http.addHeader("Content-Type", "application/json");
lv_obj_add_flag(ui_No_Result_Container, LV_OBJ_FLAG_HIDDEN);
// size_t freeHeap = ESP.getFreeHeap();
// Serial.println("Free heap before JSON parse: " + String(freeHeap));
// Send HTTP GET request
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
Serial.println("HTTP Response code: " + String(httpResponseCode));
// Get the JSON response as a string and print it
String responseString = http.getString();
Serial.println("JSON Response: " + responseString);
// Parse JSON response
DynamicJsonDocument jsonResponse(2048); // Adjust size as needed
DeserializationError error = deserializeJson(jsonResponse, responseString);
if (!error) {
// Check if "SearchResults" and "Parts" keys exist
if (jsonResponse.containsKey("SearchResults") && jsonResponse["SearchResults"].containsKey("NumberOfResult") && jsonResponse["SearchResults"].containsKey("Parts")) {
int numberOfResult = jsonResponse["SearchResults"]["NumberOfResult"].as<int>();
JsonArray parts = jsonResponse["SearchResults"]["Parts"].as<JsonArray>();
// Clear previous component data
clearComponentData();
// Create a new screen and switch to it
lv_obj_t* temp_screen = lv_obj_create(NULL);
lv_scr_load(temp_screen);
// Clean old search results safely
lv_event_send(ui_Search_Result, LV_EVENT_DELETE, NULL); // Safely remove any pending events
lv_obj_invalidate(ui_Search_Result); // Prevent any drawing operations during clean
lv_obj_clean(ui_Search_Result); // Still causes crashes (This is the line where it crashes)
if (numberOfResult > 0) {
createProductCards(ui_Search_Result, numberOfResult);
createChangePage(ui_Search_Result, numberOfResult, page);
int i = 0;
for (JsonObject part : parts) {
if (i >= MAX_COMPONENTS) break; // Ensure we don't exceed the array size
descriptions[i] = strdup(part["description"] | "");
if (!descriptions[i]) {
Serial.println("Memory allocation failed for descriptions[" + String(i) + "]");
continue;
}
manufacturers[i] = strdup(part["manufacturer"] | "");
if (!manufacturers[i]) {
Serial.println("Memory allocation failed for manufacturers[" + String(i) + "]");
free((void*)descriptions[i]);
descriptions[i] = nullptr;
continue;
}
partNumbers[i] = strdup(part["part_number"] | "");
if (!partNumbers[i]) {
Serial.println("Memory allocation failed for partNumbers[" + String(i) + "]");
free((void*)descriptions[i]);
descriptions[i] = nullptr;
free((void*)manufacturers[i]);
manufacturers[i] = nullptr;
continue;
}
manufacturerPartNumbers[i] = strdup(part["mpn"] | "");
if (!manufacturerPartNumbers[i]) {
Serial.println("Memory allocation failed for manufacturerPartNumbers[" + String(i) + "]");
free((void*)descriptions[i]);
descriptions[i] = nullptr;
free((void*)manufacturers[i]);
manufacturers[i] = nullptr;
free((void*)partNumbers[i]);
partNumbers[i] = nullptr;
continue;
}
// Print extracted data
Serial.println("Component " + String(i + 1) + ":");
Serial.println("Description: " + String(descriptions[i]));
Serial.println("Manufacturer: " + String(manufacturers[i]));
Serial.println("Manufacturer Part Number: " + String(manufacturerPartNumbers[i]));
lv_label_set_text(productCardComponents[i].Mfr_Part, manufacturerPartNumbers[i]);
lv_label_set_text(productCardComponents[i].Description, descriptions[i]);
lv_label_set_text(productCardComponents[i].Manufacturer, manufacturers[i]);
lv_label_set_text(productCardComponents[i].Part_Number, partNumbers[i]);
const char* partNumberText = lv_label_get_text(productCardComponents[i].Part_Number);
String response = "https://theyoungmaker.ddns.net/PartSense/images/" + String(partNumberText) + "/96x96.bmp";
if (getImageFromURL(response, i)) {
Serial.println("Image downloaded and processed successfully");
lv_img_set_src(productCardComponents[i].Image, &productImages[i]);
} else {
Serial.println("Failed to download or process image");
}
i++;
}
} else {
lv_obj_clear_flag(ui_No_Result_Container, LV_OBJ_FLAG_HIDDEN);
}
} else {
Serial.println("JSON response does not contain expected keys");
}
lv_obj_add_flag(ui_Spinner1, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(ui_Search_Result, LV_OBJ_FLAG_HIDDEN);
// Switch back to the original product screen
lv_scr_load(ui_Component_Search);
} else {
Serial.println("Failed to parse JSON: " + String(error.c_str()));
}
} else {
Serial.println("Error on HTTP request: " + http.errorToString(httpResponseCode));
}
http.end();
vTaskDelete(searchComponentTaskHandle);
}
void startSearchComponentTask(lv_event_t* event) {
int page = (int)lv_event_get_user_data(event);
xTaskCreatePinnedToCore(
SearchComponent, // Task function
"SearchComponentTask", // Task name
10000, // Stack size (bytes)
(void*)page, // Task parameters
1, // Priority (0 = lowest, 1 = default, 2 = highest)
&searchComponentTaskHandle, // Task handle
0 // Core to run the task on (0 or 1)
);
}
Using ESP Exception Decoder, it gives me the following with the backtrace :
0x4200fb67: _lv_event_mark_deleted at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_event.c:155
0x420125a5: lv_obj_destructor at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_obj.c:454
0x420d453f: _lv_obj_destruct at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_obj_class.c:136
0x42016e51: obj_del_core at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_obj_tree.c:385
0x42016e87: obj_del_core at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_obj_tree.c:362
0x42016e87: obj_del_core at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_obj_tree.c:362
0x42016fa1: lv_obj_clean at c:\Users\Loic\Documents\Arduino\libraries\lvgl\src\core\lv_obj_tree.c:89
0x42003186: SearchComponent(void*) at C:\Users\Loic\Downloads\LVGL_Arduino\LVGL_Arduino.ino:463