How to Solve Performance Bottlenecks in Embedded GUI Displays

In embedded GUI development, issues such as screen flickering during refresh, excessive memory usage leading to system crashes, stuttering animations, and significant performance drops during multi-screen displays are common challenges.

As a leading lightweight embedded graphics library, LVGL’s buffer management directly determines the smoothness of applications and resource consumption. Today, we will share how to optimize display performance.

How to Solve Performance Bottlenecks in Embedded GUI Displays

1. Three Core Rendering Modes of LVGL Buffers

LVGL manages display devices through the <span><span>lv_display_t</span></span> object, with three rendering modes corresponding to different hardware scenarios. Choosing the right one is half the battle!

Rendering Mode Number of Buffers Memory Usage Performance Applicable Scenarios
Partial Rendering (PARTIAL) 1 Low (only 10% of the screen) Medium Memory-constrained devices (e.g., low-end MCUs)
Direct Rendering (DIRECT) 2 Medium (2 times screen size) Good General applications (require no flickering)
Full Screen Rendering (FULL) 2-3 High (2-3 times screen size) Excellent Complex animations, high-performance requirements

Key Configuration Examples

  • Partial Rendering (Memory Optimal):
  • #define BYTES_PER_PIXEL 2  // RGB565 format
    static uint8_t partial_buf[320 * 240 / 10 * BYTES_PER_PIXEL];
    lv_display_set_buffers(disp, partial_buf, NULL, sizeof(partial_buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
  • Double Buffering (Preferred for No Flickering):
    static uint8_t buf1[320 * 240 * BYTES_PER_PIXEL];
    static uint8_t buf2[320 * 240 * BYTES_PER_PIXEL];
    lv_display_set_buffers(disp, buf1, buf2, sizeof(buf1), LV_DISPLAY_RENDER_MODE_DIRECT);

2. Resource-Efficient High Performance

1. Choosing the Right Color Format Saves Memory

The memory usage varies significantly with different color formats; in embedded scenarios, RGB565 is the preferred choice!

Color Format Bytes per Pixel Memory Usage for 320×240 Screen Visual Quality
RGB565 2B 150KB Clear enough (recommended)
RGB888 3B 225KB More accurate colors
ARGB8888 4B 300KB Includes alpha channel (memory-intensive)

2. Buffer Size Calculation Formula

uint32_t calculate_buffer_size(int32_t width, int32_t height,
                                lv_color_format_t color_format,
                                lv_display_render_mode_t mode) {
    uint32_t pixel_size = lv_color_format_get_size(color_format);
    uint32_t base_size = width * height * pixel_size;
    switch(mode) {
        case PARTIAL: return base_size / 10;  // 1/10 screen size
        case DIRECT/FULL: return base_size;   // Full screen size
        default: return 0;
    }
}

3. Dynamic Memory Allocation

// Dynamic allocation for double buffering
void init_display_buffers(lv_display_t *disp) {
    uint32_t buf_size = width * height * pixel_size;
    void *buf1 = lv_mem_alloc(buf_size);  // LVGL dedicated allocator (ensures alignment)
    void *buf2 = lv_mem_alloc(buf_size);
    if(buf1 && buf2) {
        lv_display_set_buffers(disp, buf1, buf2, buf_size, DIRECT);
    }
}

3. Hardware Acceleration + Callback Optimization

1. DMA Transfer Instead of Software Copy

Traditional software pixel-by-pixel writing is inefficient; using DMA for bulk transfers directly frees up the CPU:

void optimized_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
    my_display_data_t *dev_data = lv_display_get_driver_data(disp);
    if(dev_data->dma_available) {
        // DMA bulk transfer of pixel data
        start_dma_transfer(dev_data->dma_channel, px_map, area, dev_data->display_address);
    } else {
        // Software transfer fallback
        ......
    }
}

2. Multi-Screen Display Optimization Strategies

  • Independent Buffers: Use double buffering for the main screen (high performance) and partial rendering for the secondary screen (memory-saving)
  • // Main screen (800x480 double buffering)
    static uint8_t main_buf1[800*480*2];
    static uint8_t main_buf2[800*480*2];
    lv_display_set_buffers(main_disp, main_buf1, main_buf2, sizeof(main_buf1), DIRECT);
    // Secondary screen (240x240 partial rendering)
    static uint8_t sec_buf[240*240/10*2];
    lv_display_set_buffers(secondary_disp, sec_buf, NULL, sizeof(sec_buf), PARTIAL);
  • Memory Sharing: When resources are tight, shared memory can be split (caution required to avoid conflicts)

4. Case Study: UI Optimization for Smartwatch

Scenario Conditions

  • Screen: 240×240 RGB565 (16-bit color)

  • Memory: Only 256KB RAM

  • Requirements: Smooth animations + low power consumption

Optimization Plan

void setup_smartwatch_display() {
    lv_display_t *disp = lv_display_create(240, 240);
    #define BUF_ROWS 60  // Buffer occupies only 1/4 of the screen (240/4)
    static uint8_t buf1[240 * BUF_ROWS * 2];
    static uint8_t buf2[240 * BUF_ROWS * 2];
    // Partial rendering mode + double buffering (balance performance and memory)
    lv_display_set_buffers(disp, buf1, buf2, sizeof(buf1), PARTIAL);
    lv_display_set_refr_period(disp, 33);  // 30Hz refresh rate (low power)
}

Memory Usage Details (Perfect Control Budget)

Component Memory Usage Description
Double Buffer 57.6KB 240x60x2x2B
LVGL Core ~50KB Base library overhead
Font + Image Resources ~80KB Chinese and English fonts + UI materials
Application Data ~68.4KB Remaining available memory
Total ~256KB No memory overflow

5. Common Issues Quick Resolution

Issue Cause Solution
Screen Flickering Single buffer rendering conflicts with display Enable double buffering (DIRECT mode)
Insufficient Memory Buffer too large / improper color format Switch to PARTIAL mode + RGB565
Animation Stuttering Flush callback efficiency is low Enable DMA accelerated transfer
Poor Multi-Screen Performance All screens use the same configuration Differentiated buffer configuration for main and secondary screens

LVGL Display Optimization Practices

  1. Memory Priority: For resource-constrained devices, choose “Partial Rendering + RGB565”

  2. Performance Priority: For complex animations, choose “Double Buffering / Triple Buffering + DMA”

  3. Dynamic Adjustment: Use monitoring tools to view buffer usage in real-time (optimize if over 80%)

  4. Hardware Adaptation: Fully utilize hardware features such as DMA and shared video memory

The core of optimizing LVGL display is to find the balance between “memory usage” and “performance smoothness” under hardware constraints.

—–👇 Previous Selected Recommendations 👇—–

▶️ Embedded GUI Page Switching – Linked List Accounting Method

▶️ A Free and Modern GUI Design Accelerator
▶️ An Open Source Low-Cost Positioning System
▶️ Technical People Playing with Embedded Product AI Series
▶️ Must-Read DIY Open Source E-Book
▶️ DIY an Open Source Fully Autonomous Weather Station, Practical IoT Technology
▶️ A Long-Term Earning Guide for Tech Guys
▶️ New Choice for Open Source Quadcopters: Flix
▶️ How Interns Quickly Grow into Embedded STM32 Experts
▶️ A Ready-to-Use Monochrome Screen GUI Solution
▶️ A Smartwatch Developed with LVGL
▶️ The Dark Horse of Embedded GUI - HoneyGUI
▶️ An Embedded Operating System JxOS, Practical Guide to Embedded Development Efficiency

Leave a Comment