Description
I’m have platformio Arduino based project that is running on esp32 with ili9341 display and using lvgl 7.7.2.
I’m having a problem with memory. At some random point in time application for some reason run out of memory. Look at the log. From 11% it will jump to 100% and then esp32 will restart. I have multiple screens but when this happens only dashboard screen is on and task for refreshing labels is running.
Error log:
used: 7780 ( 11 %), frag: 3 %, biggest free: 62396, max: 71680
used: 7780 ( 11 %), frag: 3 %, biggest free: 62396, max: 71680
used: 7752 ( 11 %), frag: 1 %, biggest free: 63916, max: 71680
used: 7764 ( 11 %), frag: 2 %, biggest free: 62776, max: 71680
used: 7764 ( 11 %), frag: 2 %, biggest free: 62776, max: 71680
used: 7764 ( 11 %), frag: 2 %, biggest free: 62776, max: 71680
used: 7752 ( 11 %), frag: 1 %, biggest free: 63916, max: 71680
used: 7764 ( 11 %), frag: 2 %, biggest free: 62776, max: 71680
used: 7764 ( 11 %), frag: 2 %, biggest free: 62776, max: 71680
used: 71668 (100 %), frag: 34 %, biggest free: 8, max: 71680
E (95622) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (95622) task_wdt: - IDLE0 (CPU 0)
E (95622) task_wdt: Tasks currently running:
E (95622) task_wdt: CPU 0: gui
E (95622) task_wdt: CPU 1: loopTask
E (95622) task_wdt: Aborting.
abort() was called at PC 0x400eeb97 on core 0
Backtrace: 0x4008da1c:0x3ffbe170 0x4008dc4d:0x3ffbe190 0x400eeb97:0x3ffbe1b0 0x40084839:0x3ffbe1d0 0x400e08f2:0x3fff5740 0x400dd0d0:0x3fff5760 0x400d6c25:0x3fff5850 0x400d7b9e:0x3fff58e0 0x400d7c48:0x3fff5930 0x400d7e05:0x3fff5950 0x400d8214:0x3fff59e0 0x400e0ad7:0x3fff5a30 0x400e0bbd:0x3fff5a50 0x400d1366:0x3fff5a70 0x4008a165:0x3fff5af0
#0 0x4008da1c:0x3ffbe170 in invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:707
#1 0x4008dc4d:0x3ffbe190 in abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:707
#2 0x400eeb97:0x3ffbe1b0 in task_wdt_isr at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/task_wdt.c:252
#3 0x40084839:0x3ffbe1d0 in _xt_lowint1 at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/xtensa_vectors.S:1154
#4 0x400e08f2:0x3fff5740 in _lv_mem_buf_get at .pio/libdeps/esp32dev/lvgl/src/lv_misc/lv_mem.c:147
#5 0x400dd0d0:0x3fff5760 in draw_bg at .pio/libdeps/esp32dev/lvgl/src/lv_draw/lv_draw_rect.c:209
(inlined by) lv_draw_rect at .pio/libdeps/esp32dev/lvgl/src/lv_draw/lv_draw_rect.c:110
#6 0x400d6c25:0x3fff5850 in lv_obj_design at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_obj.c:3764
#7 0x400d7b9e:0x3fff58e0 in lv_refr_obj at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_refr.c:172
#8 0x400d7c48:0x3fff5930 in lv_refr_obj_and_children at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_refr.c:172
#9 0x400d7e05:0x3fff5950 in lv_refr_area_part at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_refr.c:172
#10 0x400d8214:0x3fff59e0 in lv_refr_area at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_refr.c:482
(inlined by) lv_refr_areas at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_refr.c:404
(inlined by) _lv_disp_refr_task at .pio/libdeps/esp32dev/lvgl/src/lv_core/lv_refr.c:203
#11 0x400e0ad7:0x3fff5a30 in lv_task_exec at .pio/libdeps/esp32dev/lvgl/src/lv_misc/lv_task.c:369
#12 0x400e0bbd:0x3fff5a50 in lv_task_handler at .pio/libdeps/esp32dev/lvgl/src/lv_misc/lv_task.c:369
#13 0x400d1366:0x3fff5a70 in gui_task(void*) at src/main.cpp:179
#14 0x4008a165:0x3fff5af0 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)
What MCU/Processor/Board and compiler are you using?
Arduino ESP32 with ILI9341 display
What do you want to achieve?
Want to figure out how to debug this and to learn more about memory management.
What have you tried so far?
Basically I was trying a lot of things but nothing works. I was trying to clean cache after lv_task_handler call.
lv_disp_clean_dcache(disp);
Code to reproduce
As I said I have dashboard and menu pages. In dashboard I will render few images and labels then I will create task to update labels. Task will be triggered every 100ms when dashboard is displayed on screen.
static void update_dasboard_labels_task(void * p) {
bool message_available = false;
struct RegulatorState state = receive_regulator_state(&message_available);
lv_mem_monitor(&mon);
lv_label_set_text_fmt(memory_label, "u: %6d (%3d %%), f: %3d %%, bf: %6d",
(int)mon.total_size - mon.free_size,
mon.used_pct,
mon.frag_pct,
(int)mon.free_biggest_size);
lv_label_set_text_fmt(up_time_label, "%d", millis());
if (message_available) {
static uint32_t prev_value = 0;
if (previous_state.requested_flow_temperature != state.requested_flow_temperature) {
lv_label_set_text_fmt(requested_flow_temperature_label, "R: %2.2f °C", state.requested_flow_temperature);
}
if (previous_state.flow_temperature != state.flow_temperature) {
lv_label_set_text_fmt(actual_flow_temperature_label, "A: %2.2f °C", state.flow_temperature);
}
if (previous_state.boiler_temperature != state.boiler_temperature) {
lv_label_set_text_fmt(boiler_flow_temperature_label, "B: %2.2f °C", state.boiler_temperature);
}
if (previous_state.outside_temperature != state.outside_temperature) {
lv_label_set_text_fmt(outside_temperature_label, "O: %2.2f °C", state.outside_temperature);
}
if (previous_state.radiator_pump_active != state.radiator_pump_active) {
lv_label_set_text_fmt(radiator_pump_active_label, "%d", state.radiator_pump_active);
}
if (previous_state.boiler_pump_active != state.boiler_pump_active) {
lv_label_set_text_fmt(boiler_pump_active_label, "%d", state.boiler_pump_active);
}
if (previous_state.state == NULL || strcmp(state.state, previous_state.state) != 0) {
lv_label_set_text_fmt(state_label, "%s", state.state);
}
if (previous_state.pid_output != state.pid_output) {
lv_label_set_text_fmt(pid_outuput_label, "PO %d", state.pid_output);
}
if (state.actuator_working) {
lv_obj_set_hidden(actuator_operating, true);
lv_obj_set_hidden(actuator_full_open, true);
lv_obj_set_hidden(actuator_full_closed, true);
if (state.actuator_direction == 0) {
lv_obj_set_hidden(actuator_arrow_left_icon, false);
lv_obj_set_hidden(actuator_arrow_right_icon, true);
} else {
lv_obj_set_hidden(actuator_arrow_left_icon, true);
lv_obj_set_hidden(actuator_arrow_right_icon, false);
}
} else {
lv_obj_set_hidden(actuator_arrow_left_icon, true);
lv_obj_set_hidden(actuator_arrow_right_icon, true);
lv_obj_set_hidden(actuator_operating, false);
}
if (state.actuator_dead_zone) {
if (state.actuator_direction == 0) {
lv_obj_set_hidden(actuator_full_open, false);
lv_obj_set_hidden(actuator_full_closed, true);
lv_obj_set_hidden(actuator_operating, true);
} else {
lv_obj_set_hidden(actuator_full_open, true);
lv_obj_set_hidden(actuator_full_closed, false);
lv_obj_set_hidden(actuator_operating, true);
}
}
lv_msgbox_set_text(error_message_box, state.info_message);
if (strcmp(state.state, "ERROR") == 0) {
if (show_info_message) {
// lv_obj_set_hidden(error_message_box, false);
lv_obj_set_hidden(warining_label, false);
}
} else {
// lv_obj_set_hidden(error_message_box, true);
lv_obj_set_hidden(warining_label, true);
show_info_message = true;
}
if (is_connected_to_wifi_network()) {
lv_obj_set_hidden(wifi_icon, false);
if (is_connected_to_mqtt_broker()) {
lv_obj_set_hidden(mqtt_icon, false);
} else {
lv_obj_set_hidden(mqtt_icon, true);
}
} else {
lv_obj_set_hidden(wifi_icon, true);
lv_obj_set_hidden(mqtt_icon, true);
}
}
previous_state = state;
}
Another problem possible memory leak
If you take a look at video you will see that every time when I switch from dashboard to menu and back every time used memory is increased and it will stay like that. If I do that 100+ times application will run out of memory.
// Open menu from dashboard page
static void open_menu_page(lv_obj_t * obj, lv_event_t event) {
if(event == LV_EVENT_CLICKED) {
lv_task_del(refr_task);
lv_obj_clean(lv_scr_act());
render_menu_page();
}
}
// Go back to dashboard page
static void back_icon_event_cb(lv_obj_t * obj, lv_event_t event)
{
if(event == LV_EVENT_CLICKED) {
lv_obj_clean(lv_scr_act());
render_dashboard_page();
}
}
Screenshot and/or video