_lv_inv_area: Asserted at expression: !disp->rendering_in_progress (Invalidate area is not allowed during rendering.) lv_refr.c:257


Hey, after successfully getting a hello world program up and running, I’m now experimenting with how to use LVGL.
I thought that I’d try to update some text in a loop, but when I do that, I run into this error:
[Error] (0.504, +504) _lv_inv_area: Asserted at expression: !disp->rendering_in_progress (Invalidate area is not allowed during rendering.) lv_refr.c:257.
What am I doing wrong here?

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

ESP32S3 + st7789

  • framework-arduinoespressif32 @ 3.0.0+sha.cceebb5
  • framework-arduinoespressif32-libs @ 5.1.0+sha.a5e3e0b90e.sha.6564ec9
  • tool-esptoolpy @ 1.40501.0 (4.5.1)
  • tool-mkfatfs @ 2.0.1
  • tool-mklittlefs @ 1.203.210628 (2.3)
  • tool-mkspiffs @ 2.230.0 (2.30)
  • toolchain-riscv32-esp @ 12.2.0+20230208
  • toolchain-xtensa-esp32s3 @ 12.2.0+20230208

What LVGL version are you using?

LVGL 9.0.1-dev+sha.e4b5386

What do you want to achieve?

Ideally, I’d like to be able to print something to the screen whenever I want, since I want to print debugging messages to the screen when necessary.

What have you tried so far?

The code I have is given below.

Code to reproduce

#include <Arduino.h>
#include <drivers/display/st7789/lv_st7789.h>
#include <lvgl.h>

#include "display.h"
#include "hardware_setup.h"

lv_obj_t* display_text;

void ui_init()
    const auto screen = lv_screen_active();
    lv_obj_set_style_bg_color(screen, lv_color_hex(0x003a57), LV_PART_MAIN);

    display_text = lv_label_create(screen);
    lv_label_set_text(display_text, "Hello, world!");
    lv_obj_set_style_text_color(screen, lv_color_hex(0xffffff), LV_PART_MAIN);
    lv_obj_align(display_text, LV_ALIGN_CENTER, 0, 0);

void setup() {
    sleep(1); // Wait a bit for Serial to become ready. Printing immediately doesn't work


void loop() {
    lv_label_set_text(display_text, "Hello, world!");


Here, Display::init() contains initialization code specific to my setup. It contains a call to lv_init() and does things like setting up my draw buffers.

Seems you dont understand how lvgl work or you start right handler in other thread, but then you require handle thread safety as in docu.

Right, I don’t quite understand how lvgl works. I’m still trying to figure that out. A walkthrough explaining not only the “what”, but also the “why” and “how” of the basic workings of lvgl would be really nice, but I haven’t found that so far.

Do you mean the timer handler? I asked about this here, but nobody has responded so far: Lv_timer_handler - What does “lower priority than lv_tick_inc()” mean? - Get started - LVGL Forum

Do you have a link to the thread safety documentation?

You : “… you need to call lv_timer_handler() periodically …”
Your code here no call?

On ESP32 you can handle tick_inc in lv_conf enable custom tick. No your code required. But handler must be called in loop or special thread.

Most simple loop

uint32_t looper5;
void loop() {


if(looper5%200 == 0)
    lv_label_set_text(display_text, "Hello, world!");


And some peaples around world write into google lvgl thread safe, but for you Operating system and interrupts — LVGL documentation

Well, as my linked question indicates, the correct usage of lv_timer_handler() is not quite clear to me.
The timer handler documentation is very sparse, mentioning only that:

To handle the tasks of LVGL you need to call lv_timer_handler() periodically in one of the following:

  • while(1) of main() function
  • timer interrupt periodically (lower priority than lv_tick_inc())
  • an OS task periodically

Therefore, I do call the function periodically using a timer interrupt:

    // Create timer
    // https://github.com/espressif/esp-idf/blob/b3f7e2c8a4d354df8ef8558ea7caddc07283a57b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c#L473
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = [](void *arg)
        lv_timer_handler(); },
        .name = "lvgl_tick"};
    esp_timer_handle_t lvgl_tick_timer = nullptr;
    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000));

This is part of the Display::init() code I mentioned in the beginning. The full code for that is here:
display.cpp (github.com)

And some peaples around world write into google lvgl thread safe, but for you Operating system and interrupts — LVGL documentation

Thanks for the link. But there’s no need for the added sass in a question asked in a beginner forum.

NO your code interrupt call in same place inc and handler ! Maybe read precisely lower priority as lv_tick_inc say cleanly you cant call on same place.

But for clean you primary need understand what you do. And for beginer is first point most simple use while… second two variant is for profesionals …

Then do what i write activate lv_conf custom tick and use loop…

And one additional info v 9.0 is born some weeks and i agree with you , documents is … For beginer i mean good start point is v 8