Hello,
I’m observing severe crashes of MBedOS (the typical red LED 4x slow and 4x fast blinking) after adjusting an LVGL slider. Mostly the problem appears in the first stages after startup of the system. I did make a stripped-down exemplary Arduino project that can be used to reproduce the issue. See at the end of this post.
It seems that the problem is some memory allocation issue in the end. Question is why this is triggered at all?
The LVGL (I’m using version 9.2.2) can be setup in ~/.arduino15/packages/arduino/hardware/mbed_giga//libraries/Arduino_H7_Video/src/lv_conf_9.h to either use its built-in memory management or the standard libc memory management. When the LVGL-builtin memory management is being used, there has to be also specified the share of memory that the LVGL will be grabbing.
In general it also seems that the crashes are not induced due to internal memory allocation of the LVGL. That is because the problems do also get worse, the larger the memory to be reserved for the LVGL is being set. The more memory is reserved for the LVGL, the less memory is available for the rest. So to me it seems that the LVGL does occasionally also use normal malloc() for some purposes - so during the manipulation of a slider.
Momentarily I’m operating the system in a fashion where I’m operating the LVGL with its own memory management while assigning only an absolute minimum of memory to it. In fact, there is just left 1kiB or so over. I can do this because the application is static and does not constantly create and destroy LVGL objects. Hence there is no heap fragmentation. This is leaving as much as possible memory for the regular heap.
This did reduce the probability of the occurrence of the problem, but from time to time it appears nonetheless. Anyway, this seems to emphasize that the problem is not related with the heap allocation of LVGL objects, but with regular memory allocations probably caused by the LVGL internally during operating the slider.
Also worth noting: For debugging purposes I did also integrate some function that can be used to regularly dump memory statistics of MBedOS. Considering the rather simple application, I’m seeing rather large jumps (several tens of kilobytes) in heap size there, which are induced during the manipulation of the slider. It is not clear to me what LVGL is doing there. But on the other hand there is also plenty of heap memory available. For instance, the sample application below in junction with 140kiB reserved for the LVGL is reporting after power-up a heap size of 163116 bytes while there would be totally 325408 bytes available. So there is twice the amount of used memory available for dynamic allocation.
I can also hardly imagine that there is some issue with heap fragmentation. This simple application is not hardly allocating/freeing memory.
Anyway. For some exemplary code see the according .ino-code below. Provided that LV_MEM_SIZE in lv_conf_9.h is set to 140kiB one should see the Arduino Giga R1 WiFi crashing after two or three manipulations of the slider.
Are there any ideas for work-arounds here?
Thanks,
Mario
// LVGL Slider Crash Demo
// Settings to play with are defines LV_USE_STDLIB_MALLOC and LV_MEM_SIZE in
// ~/.arduino15/packages/arduino/hardware/mbed_giga/<version>/libraries/Arduino_H7_Video/src/lv_conf_9.h
// With LV_USE_STDLIB_MALLOC defined as LV_STDLIB_BUILTIN the LGVL build-in memory management
// is being used. Here the LVGL is directly grabbing a part of the heap. The size of this part
// is defined by LV_MEM_SIZE then.
// When LV_MEM_SIZE ist set to 140kiB, for instance, the system is crashing after two or three
// adjustments of the slider.
#include "Arduino_H7_Video.h"
#include "Arduino_GigaDisplayTouch.h"
#include "lvgl.h"
Arduino_H7_Video Display(800, 480, GigaDisplayShield);
Arduino_GigaDisplayTouch TouchDetector;
lv_obj_t* slider1;
lv_obj_t* slider1_value_label;
static void slider1_event_cb(lv_event_t * e);
volatile float slider1_value = 0.0;
void setup_gfx() {
Display.begin();
TouchDetector.begin();
lv_obj_t * screen = lv_obj_create(lv_scr_act());
lv_obj_set_size(screen, Display.width(), Display.height());
slider1 = lv_slider_create(lv_screen_active());
lv_obj_set_width(slider1, 500);
lv_slider_set_value(slider1, 0, LV_ANIM_OFF);
lv_obj_add_event_cb(slider1, slider1_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_pos(slider1, 100, 100);
lv_obj_set_style_pad_left(slider1, 10, LV_PART_KNOB | LV_STATE_DEFAULT);
}
static void slider1_event_cb(lv_event_t * e)
{
lv_obj_t * slider = (lv_obj_t *) lv_event_get_target(e);
slider1_value = (float) lv_slider_get_value(slider);
}
void print_memory_info() {
// allocate enough room for every thread's stack statistics
int cnt = osThreadGetCount();
char text[100];
mbed_stats_stack_t *stats = (mbed_stats_stack_t*) malloc(cnt * sizeof(mbed_stats_stack_t));
cnt = mbed_stats_stack_get_each(stats, cnt);
for (int i = 0; i < cnt; i++) {
snprintf(text, 100, "Thread: 0x%lX, Stack size: %lu / %lu\r\n", stats[i].thread_id, stats[i].max_size, stats[i].reserved_size);
Serial.print(text);
}
free(stats);
// Grab the heap statistics
mbed_stats_heap_t heap_stats;
mbed_stats_heap_get(&heap_stats);
snprintf(text, 100, "Heap size: %lu / %lu bytes\r\n", heap_stats.current_size, heap_stats.reserved_size);
Serial.print(text);
}
void setup() {
Serial.begin(115200);
setup_gfx();
}
void loop() {
lv_timer_handler();
print_memory_info();
delay(100);
}