Перейти к содержимому

lvgl_demo — интерфейс на LVGL с сенсорным экраном

Экран с показаниями платы на библиотеке LVGL 9: температура кристалла, свободная память, адреса сети, графики температуры, загрузки процессора, ОЗУ и SDRAM за две минуты, переключатель светодиода. Русский текст — шрифтом TTF с SD-карты.

Дисплей RGB 800×480 (RGB050M1) — как в рецепте lcd_ltdc. Сенсорная панель GT911 — на I2C1:

Сигнал тача Вывод Контакт
SCL PB8 J1-26
SDA PB7 J1-23
INT PB9 J1-25
RST PD4 J1-17

На SD-карте — шрифты /SD/fonts/PT_Sans-Web-Regular.ttf и PT_Sans-Web-Bold.ttf (есть в архиве sd-card.zip; без них экран работает со встроенным шрифтом без кириллицы).

LVGL занимает ~240 КБ Flash, поэтому вместе со всем остальным прошивка не помещается: выключается Lua (или SSH, -DH723_WITH_SSH=OFF).

Окно терминала
cmake --preset Release -DH723_WITH_LUA=OFF -DH723_RECIPES="lvgl_demo"
cmake --build build/Release

Прошивка с SSH и LVGL — 724 КБ.

lvgl_demo: started
gt911: product 911, panel 800x480
lvgl_demo: fonts loaded in 105 ms
lvgl_demo: screen ready, full redraw 52881 us

Полная перерисовка экрана — 53 мс; дальше LVGL перерисовывает только изменившееся (раз в секунду — цифры и графики). Загрузка процессора при этом — около 5 %.

  • Задача LVGL одна. LVGL не потокобезопасна: интерфейс создаётся и меняется только в задаче lvgl, которая крутит lv_timer_handler(). Данные от других задач — через очередь или флаги, которые читает таймер LVGL (lv_timer_create).
  • Вывод — прямо в кадровые буферы LTDC (LV_DISPLAY_RENDER_MODE_DIRECT). Буферов два, в SDRAM; LVGL рисует в невидимый и сама переносит изменённые места из видимого. Функция вывода (flush в lvgl_port.c) выгружает кэш и показывает готовый буфер с ближайшего кадра (lcdShow из lcd_ltdc).
  • Кэш. Процессор рисует через кэш (write-back), а LTDC читает память напрямую, поэтому перед показом весь кэш данных (32 КБ) выгружается в SDRAM — это быстрее, чем выгружать буфер построчно. Операции DMA2D LVGL сама окружает выгрузкой и инвалидацией кэша.
  • DMA2D (LV_USE_DRAW_DMA2D) заливает прямоугольники и копирует картинки, процессору остаются буквы, скругления и линии графиков.
  • Память LVGL — в SDRAM: lv_malloc_core и соседние функции в lvgl_port.c вызывают sdramMalloc (LV_USE_STDLIB_MALLOC = LV_STDLIB_CUSTOM).
  • Шрифты с карты. Tiny TTF (LV_USE_TINY_TTF) рисует буквы из файла TTF любого размера. Файл один раз читается в SDRAM (lvglLoadFont), следующие размеры используют те же данные; нарисованные буквы кэшируются. Во Flash шрифтов нет, кроме запасного латинского.
  • Файлы для LVGL — буква S:: "S:fonts/x.ttf" открывается как /SD/fonts/x.ttf (LV_USE_FS_STDIO). Так же загружаются картинки.
  • Тач GT911 опрашивается по I2C при каждом обновлении LVGL (раз в 20 мс): регистр состояния 0x814E (бит 7 — новые данные), координаты первого касания с 0x8150, затем состояние сбрасывается записью нуля. При сбросе уровень INT задаёт адрес контроллера (0 — 0x5D). Разрешение панели контроллер хранит сам — gt911: panel 800x480.
  • Размер. В config/lv_conf.h выключены ненужные форматы пикселей программного рисования (каждый — десятки КБ), LVGL собирается с -Os (recipe.cmake).
  • Зависимости рецепта — в recipe.cmake: исходники LVGL из third_party/lvgl и драйвер дисплея из рецепта lcd_ltdc (его пример при этом не запускается).
  • Свой экран — функция buildScreen в lvgl_demo.c; документация и примеры виджетов — docs.lvgl.io.
  • Экраны можно собирать мышкой в SquareLine Studio или EEZ Studio — они выдают код на C для LVGL 9.
  • Другой шрифт — любой TTF с кириллицей на карте и путь в lvgl_demo.h. Шрифты бывают большими: для экономии SDRAM подходят версии с урезанным набором символов.
  • Картинки — PNG или BMP на карте (LV_USE_LODEPNG / LV_USE_BMP в lv_conf.h) и lv_image_set_src(img, "S:images/logo.png").
  • На той же шине I2C1 можно держать и другие датчики (например, BME280 из рецепта i2c_bme280), но HAL I2C не потокобезопасен — обращения к шине из разных задач нужно закрыть мьютексом.

Исходники рецепта: recipes/lvgl_demo