LVGL performes too many refreshes cycles for my epaper display to display one screen

Description

I’am using waveshares epaper 1.54 inch display with lvgl in zephyr.
I implemented just a simple test program which shows a simple “Hello World!” on the display (lv_label_create, lv_label_set_text,…).
The text is shown on the display. So far so good.
But until the text is displayed dozens of epaper refreshes are performed by the lvgl library.
So the display is flashing like crazy for 10 to 15 seconds until the text appears on the display.
This is because the call of lv_task_handler() results in many calls of lv_task_exec() which triggers every time some writing to the display.
My question is if it is possible to do just do one write to the display after I performed the changes of the framebuffer?

What MCU/Processor/Board and compiler are you using?

Nordic nRF52840DK

What LVGL version are you using?

I’am using the LVGL library shipped with Zephyr 2.60

What do you want to achieve?

I want to achivee what the epaper display is refreshed only once by LVGL after I painted the new content on the screen.

What have you tried so far?

A lot of googeling.

Code to reproduce

The code block(s) should be formatted like:

#include <device.h>
#include <drivers/display.h>
#include <lvgl.h>
#include <stdio.h>
#include <string.h>
#include <zephyr.h>

#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(app);

void main(void)
{
	const struct device *display_dev;

	display_dev = device_get_binding(CONFIG_LVGL_DISPLAY_DEV_NAME);

	if (display_dev == NULL) {
		LOG_ERR("device not found.  Aborting test.");
		return;
	}
	
        // Display Hello World
        lv_obj_t *hello_world_label;
        hello_world_label = lv_label_create(lv_scr_act(), NULL);
        lv_label_set_text(hello_world_label, "Hello world!");
        lv_obj_align(hello_world_label, NULL, LV_ALIGN_CENTER, 0, 0);
        //lv_label_set_long_mode(hello_world_label, LV_LABEL_LONG_CROP);
        lv_obj_set_width(hello_world_label, 100);
        lv_label_set_align(hello_world_label, LV_LABEL_ALIGN_LEFT);

	lv_task_handler();
}

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.

You should be able to get around this by only sending changes to the eInk display when monitor_cb (a callback on the display driver structure) is called. That callback is only invoked once an entire “frame” has been drawn from LVGL’s perspective. Depending on how your hardware works, this may involve keeping your own framebuffer and synchronizing with the eInk one in that callback. On the last eInk display I worked with (a Kobo e-reader), Linux handled this for me, and I just had to use an ioctl to make the changes visible on the actual display.

Hi embeddedt,
thanks for the tip with the monitor_cb() method.
I did some tries and the behavior of this method is as you told. But while testing this approach I found an easier way for me to achieve my goal of having LVGL update my e-ink display only once per frame.
I have noticed that the size of the LVGLs display buffer was only 16% of my screen size by default.
Therefore LVGL was sending the data of the whole frame in 7 chunks to the display, resulting in 7 calls of display_write().
But fortunately where is a LVGL parameter (CONFIG_LVGL_VDB_SIZE) which defines the buffer display percentage. I set this parameter to 100 and now the display is refreshed only once per frame or better said per lv_task_handler() call.
Thanks and regards

1 Like