VI / EN
Quay lại danh sách ghi chú

Mastering Embedded GUI with LVGL & ILI9341 on ESP32

Technical notes on driving a 2.8-inch SPI TFT LCD with LVGL v8/v9, configuring SPI DMA buffers, optimizing FreeRTOS multitasking, and designing slick dark-mode gauge widgets.

May 18, 2026
LVGLESP32Embedded GUIFreeRTOSSPI DMA

Why LVGL for Embedded Displays?

Modern embedded consumer hardware demands responsive graphical interfaces comparable to smartphone screens. When developing the Breezi Air Purifier, an old-school 16x2 character LCD was insufficient to display PM2.5, PM10, temperature, humidity, and filter life simultaneously.

LVGL (Light and Versatile Graphics Library) provides an open-source, memory-efficient C graphics engine that brings anti-aliased fonts, animations, and touch controls to microcontrollers with modest RAM.

Optimizing SPI Throughput with DMA

A frequent bottleneck when running 320x240 RGB565 screens on microcontrollers is frame tearing and sluggish redraws. Each full frame transfer requires:

320 × 240 × 2 bytes = 153,600 bytes

To achieve a silky smooth 30+ FPS refresh without starving the CPU:

  1. SPI Frequency: Configured the ESP32 VSPI peripheral clock to 40MHz.
  2. Double DMA Buffering: Allocated two partial-frame buffers in internal SRAM (320 x 20 lines each). While DMA asynchronously pushes Buffer A to the ILI9341 display controller, LVGL renders the next dirty rectangle into Buffer B.
  3. SPI Transaction Overhead: Minimized CS toggling by bursting contiguous scanlines.

FreeRTOS Multitasking Architecture

Running GUI rendering on the same thread as sensor reading will cause erratic display stutters whenever a sensor blocks on I2C/UART.

We structured the firmware into decoupled tasks:

  • Core 0 - Sensor & Communication Task: Polls PMS5003 and SHT31, filters raw ADC data, and posts state updates to a FreeRTOS Queue.
  • Core 1 - LVGL Render Task: Dedicated solely to handling lv_timer_handler() and touch input polling every 10ms.

This isolation guarantees that the UI remains fluid even during intensive network activity or sensor calibration routines.