Lv_obj_set_hidden inconsistent results

Description

I’m currently writing an application on the ESP32 and using LVGL to drive a display. One feature of the application is to have a button press cause the application to cycle between two modes and the screen updates to reflect a different positioning of objects/values based on the mode. The way I structured the application was to create all of my objects at the start of the application and store them in an array and then when cycling between modes, call lv_obj_set_hidden() for every object in the array before drawing new values on the screen. For some reason, this doesn’t work consistently.

Say you’re going from mode 1 to mode 2. A loop sets all objects in the array to hidden. Objects that are displayed in mode 1 and have now been set to hidden are still shown on the screen in mode 2. Just to make sure that there wasn’t some weird race condition occurring in my application, as new values were being displayed in the new mode, I manually called lv_obj_set_hidden() on one of the objects that doesn’t disappear. It remained on the screen.

Going back to mode 1 will then “un-hide” this object because new values are being printed with it and if I go back to mode 2, there’s a 50/50 chance that it will actually become hidden or just stay there again. This effect is observable with objects from either mode remaining on the new mode’s screen (ie. mode 1 → mode 2 or mode 2 → mode 1).

My best guess here is that when lv_obj_set_hidden is called, LVGL somehow misses it but still marks it as hidden? Without knowing how the invalidation process works, that assumption might make no sense. I’m struggling to find anything wrong with the actual application however.

If this isn’t enough information to do anything useful with, let me know. Unfortunately this isn’t a project that I can disclose much information on.

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

ESP32

What LVGL version are you using?

7.11

EDIT: I was able to confirm the following behavior:

  1. I press the button to go from mode 1 to mode 2
  2. All values are set to hidden in the object array
  3. When values are shown in mode 2, I manually set one value from mode 1 to not be hidden again and then re-hide it ~25ms later. This value is reliably hidden.

Switching back to manually hiding it in mode 2 and not attempting to “unhide” it first, results in the value remaining in the background. So for some reason LVGL believes this value is hidden without actually removing it from the screen. Manually un-hiding it and then hiding it again seems to trigger a proper invalidation. This isn’t a workaround I can use in production however.

Are you using threads/interrupts/an OS, or is everything single-threaded?

I’m using the FreeRTOS variant in the espressif SDK. Originally I was using the dual-core configuration and pinning the task that calls lv_task_handler to core 0. That obviously didn’t fix the issue so I put the whole chip into single-core mode and the issue persists.

I can also add that I use the simulator to figure out the correct positioning of objects in each mode before implementing things on the ESP32. On the simulator side, it’s just a while loop that checks for a keyboard press and when it detects this, it sets everything to hidden before displaying the new objects. I’ve never seen the behavior I’ve described above in the simulator. So I guess it’s some combination of the ESP32 and LVGL.

I do the same on ESP32 and don’t experience this problem, make sure the main loop can execute the screen updates. If the you manipulate the gui from an other thread make sure to use semaphores to make it thread save
xSemaphoreTake(GuiBinarySemaphore, portMAX_DELAY);|
lv_task_handler();|
xSemaphoreGive(GuiBinarySemaphore);|

How are you writing text to the display in your configuration?

I have a single task that receives messages via a queue and then places text/objects via the LVGL API. The flush callback is then called from a separate task that is periodically calling lv_task_handler and sends the frame buffer over SPI using DMA. I don’t think I’m doing anything fancy here so this is making me lose my mind a bit. As far as LVGL is concerned, right up into the flush callback, the objects are “hidden” despite being visible on the display.

Switching to a polling transmit instead of a DMA transmit seems to have fixed the issue. For now this will work I guess

I use TFT_eSPI library for TFT (arduino) you can check source code on GitHub - paulh002/VFO-ESP32-Si5351: VFO ESP32 Si5351 if necessary.