本文记录在 STM32H7S78-DK 开发板(STM32H7S7L8,Cortex-M7 @600MHz,800×480 RGB 屏 + GT911 触摸)上运行 LVGL 图形界面的完整流程。由于 LVGL 应用远超片内 64KB Flash,采用「MCUboot + 外部 Octo-SPI Flash」方式运行,帧缓冲放在板载 32MB PSRAM。
环境基于上一篇《STM32H7S78-DK上跑通Zephyr:从Blinky到外部Flash启动-电子产品世界论坛》搭建的 Windows + Zephyr 4.5 工作区(D:\luglZephyrproject)。

1. Demo 源码解析
工程放在 app/lvgl_demo,只有三个文件。
prj.conf —— 打开显示、输入和 LVGL;触摸通过板级 DTS 的 zephyr,touch chosen 节点自动接管;色深必须与 LTDC 面板一致(RGB888,24bit),否则花屏:
CONFIG_MAIN_STACK_SIZE=4096 CONFIG_LOG=y CONFIG_DISPLAY=y CONFIG_INPUT=y CONFIG_LVGL=y CONFIG_LV_Z_MEM_POOL_SIZE=58368 CONFIG_LV_Z_POINTER_FROM_CHOSEN_TOUCH=y # LTDC 面板为 RGB888(24bit) CONFIG_LV_COLOR_DEPTH_24=y CONFIG_LV_FONT_MONTSERRAT_24=y CONFIG_LV_FONT_MONTSERRAT_32=y
CMakeLists.txt —— 与所有 Zephyr 应用同构:
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(lvgl_demo)
target_sources(app PRIVATE src/main.c)src/main.c —— 创建一个标题、一个触摸计数按钮和一个滑动条。要点:所有 LVGL API 调用必须包在 lvgl_lock() / lvgl_unlock() 之间,主循环周期调用 lv_timer_handler():
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/display.h>
#include <zephyr/logging/log.h>
#include <lvgl.h>
#include <lvgl_zephyr.h>
LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);
static lv_obj_t *count_label;
static lv_obj_t *slider_label;
static void count_btn_event_cb(lv_event_t *e)
{
static uint32_t count;
char buf[32];
count++;
snprintf(buf, sizeof(buf), "Count: %u", count);
lv_label_set_text(count_label, buf);
}
static void slider_event_cb(lv_event_t *e)
{
lv_obj_t *slider = lv_event_get_target(e);
char buf[32];
snprintf(buf, sizeof(buf), "Slider: %d", (int)lv_slider_get_value(slider));
lv_label_set_text(slider_label, buf);
}
int main(void)
{
const struct device *display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
lv_obj_t *btn;
lv_obj_t *btn_label;
lv_obj_t *slider;
if (!device_is_ready(display_dev)) {
LOG_ERR("display device not ready");
return 0;
}
lvgl_lock();
lv_obj_t *title = lv_label_create(lv_screen_active());
lv_label_set_text(title, "STM32H7S78-DK LVGL Demo");
lv_obj_set_style_text_font(title, &lv_font_montserrat_32, 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 40);
count_label = lv_label_create(lv_screen_active());
lv_label_set_text(count_label, "Count: 0");
lv_obj_set_style_text_font(count_label, &lv_font_montserrat_24, 0);
lv_obj_align(count_label, LV_ALIGN_CENTER, 0, -60);
btn = lv_button_create(lv_screen_active());
lv_obj_set_size(btn, 200, 60);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);
lv_obj_add_event_cb(btn, count_btn_event_cb, LV_EVENT_CLICKED, NULL);
btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "Click me!");
lv_obj_set_style_text_font(btn_label, &lv_font_montserrat_24, 0);
lv_obj_center(btn_label);
slider_label = lv_label_create(lv_screen_active());
lv_label_set_text(slider_label, "Slider: 0");
lv_obj_set_style_text_font(slider_label, &lv_font_montserrat_24, 0);
lv_obj_align(slider_label, LV_ALIGN_CENTER, 0, 100);
slider = lv_slider_create(lv_screen_active());
lv_obj_set_size(slider, 400, 20);
lv_obj_align(slider, LV_ALIGN_CENTER, 0, 150);
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_timer_handler();
lvgl_unlock();
display_blanking_off(display_dev);
LOG_INF("lvgl demo started");
while (1) {
lvgl_lock();
lv_timer_handler();
lvgl_unlock();
k_msleep(10);
}
return 0;
}板子的显示能力全部由板级 DTS 描述:LTDC 控制器(800×480 RGB888,ext-sdram = <&psram> 指定帧缓冲在 PSRAM)、GT911 触摸、背光/使能 GPIO,应用代码无需任何板级修改。
2. 编译与烧录(外部 Flash 方式)
在 CMD 中执行:
cd /d D:\luglZephyrproject set ZEPHYR_SDK_INSTALL_DIR=D:\luglZephyrproject\zephyr-sdk-1.0.1\zephyr-sdk-1.0.1 set ZEPHYR_TOOLCHAIN_VARIANT=zephyr :: Sysbuild 一次构建 MCUboot + 签名应用(LVGL 镜像约 400KB,放不进片内 64KB) west build -b stm32h7s78_dk/stm32h7s7xx/ext_flash_app --sysbuild -s D:\STM32\stm32H7S78-dk\app\lvgl_demo -d D:\STM32\stm32H7S78-dk\app\lvgl_demo\build :: 首次烧录:MCUboot + 应用两个镜像一起烧 west flash -d D:\STM32\stm32H7S78-dk\app\lvgl_demo\build :: 以后改代码只重烧应用(引导器不动): west flash -d D:\STM32\stm32H7S78-dk\app\lvgl_demo\build --domain lvgl_demo
烧录后复位,屏幕显示标题、按钮和滑动条,触摸点击按钮计数递增,拖动滑动条数值实时更新;串口(ST-LINK VCP,115200)可见启动链:
I: Starting bootloader I: Jumping to the first image slot *** Booting Zephyr OS build v4.5.0 *** [00:00:00.xxx] <inf> app: lvgl demo started
3. 踩坑记录
色深必须匹配面板:LTDC 是 RGB888,CONFIG_LV_COLOR_DEPTH_24=y 不能少,否则画面异常。
镜像放不下就换变体:普通 stm32h7s78_dk 目标只有 64KB Flash,LVGL 必须用 ext_flash_app 变体 + --sysbuild。
签名依赖:sysbuild 构建用 imgtool 给应用签名,需要提前 pip install -r bootloader\mcuboot\scripts\requirements.txt。
切变体要清缓存:同一 build 目录换板级变体时加 -p,否则 CMake 报 board 不匹配。
触摸开箱即用:LV_Z_POINTER_FROM_CHOSEN_TOUCH=y 直接把板级 zephyr,touch 节点注册为 LVGL 指针输入,无需手写触摸驱动对接代码。
我要赚赏金
