Use LVGL as not fullscreen and stop it or reuse it

I’m new to using LVGL,I’m looking for a way to display only a portion of the LVGL and the rest to be drawn on LCD.What I want to achieve is to switch the UI drawn by LCD, LVGL only uses the Roller, and it may be possible to switch to a different LVGL screen when switching, or not to use LVGL for the time being. At the same time, these two are on both FreeRtos threads.The screen only uses touch, and I don’t know if this is possible. If so, what does the proposed solution look like? Is there still page management where feasible?

Hi,

Yes, this architecture is possible, but there are a few things to consider.

LVGL is designed to work on top of your existing low-level display drivers. It renders into a draw buffer and then calls the display flush callback, so your existing LCD rendering code can coexist with LVGL.

For your use case, I would suggest the following approach:

  1. Use LVGL only for a specific region

LVGL doesn’t have a built-in mechanism to restrict the entire display to a specific sub-region, but you can achieve this in the display flush callback.

You can define the region owned by LVGL and only flush areas that fall within that region. You can also create the LVGL display with the size of the region you want LVGL to control and then offset the coordinates in the flush callback to map them to the correct position on the physical LCD.

  1. Render the rest of the display directly

Your existing application can continue rendering the parts of the LCD that are not controlled by LVGL. You just need to make sure that your direct rendering does not conflict with LVGL’s flush operations.

  1. Temporarily stop using LVGL

If you don’t need LVGL for a certain period, you can simply stop calling lv_timer_handler(). This will prevent LVGL from processing timers, input, and rendering.

When you want to use LVGL again, you can resume calling lv_timer_handler().

There isn’t really a built-in “pause rendering” API, so stopping the LVGL handler loop is probably the simplest approach.

  1. Handle touch input

LVGL’s input device read callback is processed by lv_timer_handler(). Therefore, if you stop calling it, LVGL will no longer process touch input.

I would recommend reading the touch input independently from LVGL and then routing the touch events depending on the current mode:

  • LVGL active → provide the input to LVGL.

  • LVGL inactive → handle the touch events in your application.

  1. FreeRTOS synchronization

LVGL is not thread-safe, so all LVGL API calls should be performed from a single LVGL task, or protected by a mutex.

For example, you could have a dedicated LVGL task that periodically calls lv_timer_handler(). If another FreeRTOS task needs to modify an LVGL object, it should acquire the same mutex before calling any LVGL API.

It’s important that you don’t have two different tasks directly calling LVGL APIs at the same time.

  1. Screen/page management

You can still use LVGL’s normal screen management, such as lv_scr_load() and lv_scr_load_anim(). These should be called from the LVGL task, or from another task while holding the LVGL mutex.

So, in summary, I think the architecture could look like this:

  • LVGL region: LVGL renders only the area assigned to it, with the flush callback mapping that region to the physical LCD.

  • Rest of the LCD: Your existing application renders these areas directly.

  • LVGL inactive: Stop calling lv_timer_handler() and handle the display and touch input directly.

  • Touch: Read the touch controller independently and route input either to LVGL or your application depending on the active mode.

  • FreeRTOS: Use a dedicated LVGL task and protect all LVGL API calls with a mutex.

  • Pages/screens: Continue using LVGL’s built-in screen management normally.

The main thing I would be careful about is ensuring that the direct LCD rendering and LVGL’s flush callback never access or modify the display at the same time. You will likely need some synchronization mechanism around the LCD driver as well.