I’m using LVGL 9.2 on ESP32 (FreeRTOS/Arduino).
My project runs out of memory within a few minutes.
I’m using LV_STDLIB_CLIB because I saw a recommendation for this with ESP32, but it seems that it precludes use of lv_mem_monitor().
I’ve also set #define LV_USE_OS LV_OS_FREERTOS
My code reports lots of free heap space when the errors start:
Free heap: 95888 bytes
~[Warn] (14.800, +14800) lv_draw_buf_create_ex: No memory: 143x53, cf: 16, stride: 572, 30316Byte, lv_draw_buf.c:287
[Warn] (14.800, +14800) lv_draw_buf_create_ex: No memory: 143x53, cf: 16, stride: 572, 30316Byte, lv_draw_buf.c:287
[Warn] (14.800, +0) lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later lv_draw.c:408
[Warn] (14.800, +0) lv_draw_layer_alloc_buf: Allocating layer buffer failed. Try later lv_draw.c:408
I’m drawing some text, an arc and some tics, and moving a needle.
Not sure why this code would be consuming more memory each cycle. Any recommendations for either a) enabling memory usage monitoring or b) garbage collection/cleanup I can do manually?
Below is my GUI create code and my update code which is called once per second.
void lv_create_main_gui(void) {
screen = lv_screen_active();
lv_obj_set_style_bg_color(screen, lv_color_black(), 0);
lv_style_init(&style);
lv_style_set_text_color(&style, lv_color_hex(yellow));
lv_style_init(&style_large_font);
lv_style_set_text_font(&style_large_font, &lv_font_montserrat_16);
//lv_style_set_text_font(&style_large_font, &lv_font_unscii_16);
data_label = lv_label_create(screen);
lv_obj_add_style(data_label, &style, 0);
lv_obj_add_style(data_label, &style_large_font, 0);
lv_label_set_long_mode(data_label, LV_LABEL_LONG_WRAP);
lv_obj_set_width(data_label, SCREEN_WIDTH);
// create a "scale""
lv_obj_t *scale_line = lv_scale_create(lv_screen_active());
lv_obj_set_size(scale_line, SCREEN_WIDTH*6/10, SCREEN_WIDTH*6/10);
lv_scale_set_mode(scale_line, LV_SCALE_MODE_ROUND_OUTER);
lv_obj_set_style_bg_opa(scale_line, LV_OPA_TRANSP, 0);
//lv_obj_set_style_bg_opa(scale_line, LV_OPA_50, 0); // uncomment to see whole circle
lv_obj_set_style_arc_color(scale_line, lv_color_hex(yellow), LV_PART_MAIN);
lv_obj_set_style_arc_width(scale_line, 4, LV_PART_MAIN);
lv_obj_set_style_line_color(scale_line, lv_color_hex(yellow), LV_PART_MAIN);
lv_obj_set_style_line_color(scale_line, lv_color_hex(yellow), LV_PART_ITEMS);
lv_obj_set_style_text_color(scale_line, lv_color_hex(yellow), 0);
lv_obj_set_style_radius(scale_line, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_clip_corner(scale_line, true, 0);
//lv_obj_align(scale_line, LV_ALIGN_BOTTOM_MID, LV_PCT(2), 0);
lv_obj_align(scale_line, LV_ALIGN_BOTTOM_MID, 0, -SCALE_BOT_OFFSET);
lv_scale_set_label_show(scale_line, false);
lv_obj_set_style_text_color(scale_line, lv_color_hex(yellow), 0);
lv_obj_set_style_line_color(scale_line, lv_color_hex(yellow), LV_PART_MAIN);
lv_obj_set_style_line_color(scale_line, lv_color_hex(yellow), LV_PART_ITEMS);
lv_obj_set_style_line_color(scale_line, lv_color_hex(yellow), LV_PART_INDICATOR);
lv_obj_set_style_length(scale_line, 5, LV_PART_ITEMS);
lv_obj_set_style_length(scale_line, 10, LV_PART_INDICATOR);
lv_scale_set_range(scale_line, 90, -90);
lv_scale_set_angle_range(scale_line, 180);
lv_scale_set_rotation(scale_line, 0);
// create label for scale (rotation)
rotation_label = lv_label_create(lv_screen_active());
lv_label_set_text(rotation_label, "0");
lv_obj_set_style_text_color(rotation_label, lv_color_hex(yellow), 0);
lv_obj_align_to(rotation_label, scale_line, LV_ALIGN_BOTTOM_MID, -10, SCALE_BOT_OFFSET);
// Create the needle line
needle_line = lv_line_create(scale_line);
lv_obj_set_style_line_color(needle_line, lv_color_hex(yellow), LV_PART_MAIN);
lv_obj_set_style_line_width(needle_line, 3, LV_PART_MAIN); // thinner
lv_obj_set_style_line_rounded(needle_line, true, LV_PART_MAIN);
update_needle_position(0);
}
char bufB[128], bufS[64];
unsigned long uptime;
//lv_mem_monitor_t mon;
void LVGLdataWindDebug() {
uptime = millis() / 1000;
sprintf(bufB, "Uptime: %lu\n", uptime % 10000);
sprintf(bufS, "Wifi: %s\n", (WiFi.status() == WL_CONNECTED) ? WiFi.SSID().substring(0,7).c_str() : "----");
strcat(bufB, bufS);
#ifdef N2K
sprintf(bufS, "N2K: %d:%d\n", n2k::num_n2k_messages % 10000, 0);
strcat(bufB, bufS);
sprintf(bufS, "Wind: %d:%d\n", n2k::num_wind_messages % 10000, 0);
strcat(bufB, bufS);
sprintf(bufS, "AWS:%2.1f\n", n2k::windSpeedKnots);
strcat(bufB, bufS);
sprintf(bufS, "AWA:%2.0f\n", n2k::windAngleDegrees);
strcat(bufB, bufS);
#endif
lv_label_set_text(data_label, bufB);
#ifdef N2K
// update label at bottom of gauge
snprintf(bufB, sizeof(bufB), "%0.2f", n2k::rotateout);
lv_label_set_text(rotation_label, bufB);
update_needle_position(n2k::rotateout);
#endif
if (uptime % 5 == 1) {
//lv_mem_monitor(&mon);
//Serial.printf("Total: %d bytes, Free: %d bytes, Max used: %d bytes, Used percentage: %d%%\n", mon.total_size, mon.free_size, mon.max_used, mon.used_pct);
Serial.println("Free heap: " + String(ESP.getFreeHeap()) + " bytes");
}
}