I have a project that uses ESP32S3 with SPI AMOLED display.
The screen is going to contain a number of usual widgets, text and graphical indicators, for which I would like to use lvgl, for painless rendering of the text and for antialiasing. These elements are rarely updated, and rendering is allowed to be slow.
Another, big, section of the screen will display oscilloscope-type trace of a real-time signal. The target is to draw the next, approximately 1.5K pixels, strip 25 times per second.
For this “fast” display, I do not want any blending, object overlap detection, or canvas buffers. Full image will only exist in the display controller RAM, and not take MCU resources to maintain.
After reading documentation, it seems that the usual advice to use canvas does not fit my use case, and I could not find anything else suitable.
My question:
What could be a reasonable way to achieve this, without totally breaking off with lvgl and resorting to display driver primitives?
Draw callback functions look promising. Would I be able to define a custom draw event callback on an object covering the “fast display area” maybe? Are such callbacks allowed to use “display flash” callback? How to control when exactly will it run?
I ended up with the code that, in the main loop, first calls lv_task_handler(), and after that, the driver function that updates the area (the same function that is registered with lv_display_set_flush_cb()).
Ugly, but I could not come up with anything better.
To make this report complete: I came up with an idea how it should be possible to solve my task with lvgl proper, without “punching holes in layers”. It almost works, but does not.
Because at every update a specific slice of the screen needs to be redrawn, I created an array of objects, one per slice, with a draw callback to redraw the curve in this slice. On each update, I passed new data to one slice object and invalidated it to trigger redraw.
It worked, rather slow, in a small test, but ran out of memory with 75 slices with 6 lines in each. So I had to fall back to the ugly way, with direct use of the display driver API.
As a side note, I was a little dismayed when I realized that lvgl uses malloc and does not check if allocation succeeded…
src/draw/lv_draw.c:95
(I did not check that it was new_task fault and not coords, but it did work with smaller number of elements. I think that coords was not at fault. It was a simple local variable in the code.)
lv_malloc_zeroed I am sure has an assert wrapper in that function that tests if the allocation was successful. It is something that is able to be turned on and off. You would have to look in your lv_conf.h file to see if the allocation checks are turned on/off.
I use lvgl as “managed component” in esp-idf, and don’t change any settings other that which fonts to include. It may be that they turn off checks by default (which is probably unwise)…