Memory corruption when cleaning screen

Description

Hi! I am running into an issue when alternating between two different GIFs on an active screen. I have tried getting this to work on both the ESP32 Lyra-T board and the ESP32-S3-Box by assigning callbacks to two different button presses, each time cleaning the currently active screen before displaying a GIF. Right now, I have guiTask pinned to Core 1 on the esp32, and am using a semaphore for lv_task_handler().

When alternating between two button presses, the program crashes in a somewhat random manner, sometimes crashing on the first button press and other times after having pressed either or both buttons several times. I have also gotten different backtraces and different error codes (InstrFetchProhibited, LoadProhibited, StoreProhibited, IntegerDivideByZero).

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

ESP32 Lyra-T & ESP32-S3-Box/gcc

What LVGL version are you using?

9.0.0, but getting the same error with 8.3.1

What do you want to achieve?

I have 2 buttons on the ESP32 Lyra-T board that I use for displaying 2 different GIFs. I would like to be able to alternate between two button presses, each time cleaning the active screen and displaying the new GIF.

What have you tried so far?

I have tried using semaphores/mutexes and pin the guiTask to Core 1 on the ESP32 (using a semaphore with lv_task_handler() inside guiTask). I have also tried creating 2 screens, each time loading the new screen before deleting the old one.

I have also tried displaying text instead of GIFs, and have observed the same errors.

As a last ditch effort, I went into menuconfig to set main task core affinity to “no affinity” on the Lyra-T, which helped a lot (program hardly crashed), but doing the same on the s3 box didn’t help at all, leaving me to believe I just got lucky.

Code to reproduce

Inside guiTask, which is pinned to core 1:

while (1) {
        /* Delay 1 tick (assumes FreeRTOS tick is 10ms */
        vTaskDelay(pdMS_TO_TICKS(10));

        /* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
        }

One of the two callbacks for each button press (other call back is structured the same way):

lv_obj_t * img;

lv_obj_clean(lv_scr_act());

img = lv_gif_create(lv_scr_act());
lv_gif_set_src(img, &robot_gif);
lv_obj_align(img, LV_ALIGN_CENTER, 0, 0);

Screenshot and/or video

Some examples of the errors:

Just a guess but you don’t need to perform lv_obj_clean. If you think about what’s happening here…button press, callback, delete everything (including the button that has just been pressed, the one associated with this callback) BOOM!

Thank you for your input. I was under the impression that lv_obj_clean only deletes the children of the passed in object, without deleting the actual object…Is there a better way to clear the screen before displaying another gif? Leaving out lv_obj_clean just stacks the gifs on top of each other.

You are correct in your understanding of lv_obj_clean but the thing you are passing in (the active screen) is the parent of everything. You are better off just changing the source for the gif each time and making img a file scope variable (so you’re not constantly deleting and recreating a gif). Another function for managing object lifetime is lv_obj_del which may be of use.

Man…I was really hoping that would work. It didn’t even occur to me to do it that way. Unfortunately, even after implementing the changes you suggested (making img global, and just changing the source in the callbacks instead of doing lv_bj_clean) I’m still faced with the same errors.

The last thing I can suggest is to use a simulator which will eliminate any suspect implementation wrt hardware. I always create the complete UI in a sim before deploying to hw for this reason.

Thank you. I will try that. Also trying to get jtag set up on the s3 box so I can walk some code.

Figured out what was going on so marking this resolved. For anyone else facing the same type of issue, just wrap any lv calls in your callback functions with the semaphore to make sure they don’t interfere with anything lv_task_handler is doing.

For example, in my callback function above, I made changes like so:

lv_obj_t * img;

while (xSemaphoreTake(xGuiSemaphore, portMAX_DELAY) != pdTRUE) {}

lv_obj_clean(lv_scr_act());

img = lv_gif_create(lv_scr_act());
lv_gif_set_src(img, &robot_gif);
lv_obj_align(img, LV_ALIGN_CENTER, 0, 0);

xSemaphoreGive(xGuiSemaphore);