news 2026/7/10 6:45:08

LVGL移植小记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LVGL移植小记

RISC-V移植LVGL图形库实践记录

背景

最近在一个RISC-V项目上需要用到图形界面,选用了LVGL。移植过程遇到了一些问题,记录下来供参考。本文以CH32V307为例,LVGL版本为v7.11.0。不同版本之间接口可能有差异,请注意对应。

一、准备工作

硬件

  • 主控:RISC-V MCU(CH32V307)
  • 显示屏:TFT LCD(SPI或并口均可)
  • 调试工具:USB转串口、下载器

软件

  • IDE:MounRiver Studio
  • 编译器:RISC-V GCC
  • 源码:LVGL核心库 + 官方Demo

前置条件

建议先确保以下几点:

  • 能正常编译烧录一个简单的裸机工程(如点灯)
  • LCD底层驱动已经调通,能正常画点、填充颜色
  • 对C语言和嵌入式开发有一定基础

二、获取源码

从GitHub克隆在国内可能较慢,可以通过官方镜像下载:
wget https://download.lvgl.io/lvgl/v7/lvgl-v7.11.0.tar.gz
wget https://download.lvgl.io/demos/v7/lv_demos-v7.11.0.tar.gz

注意核心库与Demo版本需要保持一致,否则可能出现运行时错误。解压后得到lvgllv_demos两个文件夹。

三、工程目录结构

建议按以下方式组织文件:

Project/
├── Drivers/ # LCD、触摸等硬件驱动
│ ├── lcd.c
│ ├── lcd.h
│ └── touch.c
├── GUI/ # LVGL相关
│ ├── lvgl/ # 核心库
│ ├── lvgl_port/ # 移植层(显示、输入驱动)
│ └── lv_demos/ # 示例代码
├── User/
│ └── main.c
└── lv_conf.h # LVGL配置文件

这样区分便于维护,后续升级时也容易替换。

四、配置LVGL

4.1 复制配置文件

lvgl/lv_conf_template.h复制到工程根目录,重命名为lv_conf.h
lv_demos/lv_examples/lv_ex_conf_template.h复制到工程根目录,重命名为lv_ex_conf.h

4.2 修改 lv_conf.h

打开lv_conf.h,将开头的#if 0改为#if 1启用配置。根据实际硬件修改以下参数(以240×480分辨率、16位色深为例):

/* 屏幕分辨率 */
#define LV_HOR_RES_MAX 240
#define LV_VER_RES_MAX 480

/* 颜色深度:16位RGB565 */
#define LV_COLOR_DEPTH 16

/* DPI设置,适合小尺寸屏幕 */
#define LV_DPI 130

/* 内存配置:根据实际RAM大小调整 /
#define LV_MEM_SIZE (24U * 1024U) / 24KB足够运行Widgets Demo */
#define LV_MEM_CUSTOM 0

/* 显示刷新周期:30ms ≈ 33FPS */
#define LV_DISP_DEF_REFR_PERIOD 30

如果出现画面撕裂,可以尝试增加刷新周期或减小缓冲区大小,最后再考虑增大LV_MEM_SIZE

4.3 修改 lv_ex_conf.h

打开lv_ex_conf.h,同样将#if 0改为#if 1,根据需要开启对应的Demo宏。

五、移植显示驱动

这是移植的核心部分,需要实现一个disp_flush函数,将LVGL的绘制数据输出到LCD。

5.1 准备移植文件

lvgl/examples/porting/目录下:

  • lv_port_disp_template.clv_port_disp.c
  • lv_port_disp_template.hlv_port_disp.h
  • lv_port_indev_template.clv_port_indev.c(如需触摸)
  • lv_port_indev_template.hlv_port_indev.h(如需触摸)

5.2 实现显示驱动

打开lv_port_disp.c

  1. 将文件开头的#if 0改为#if 1
  2. 包含LCD驱动头文件:

#include “lv_port_disp.h”
#include “lcd.h”

  1. 定义显示缓冲区。LVGL提供了三种方案:

/* 方案1:单缓冲,最简单,适合资源极紧张的场合 */
static lv_color_t draw_buf_1[LV_HOR_RES_MAX * 10];
lv_disp_buf_init(&draw_buf_dsc_1, draw_buf_1, NULL, LV_HOR_RES_MAX * 10);

/* 方案2:双部分缓冲,推荐,兼顾性能与内存 */
static lv_color_t buf_2_1[LV_HOR_RES_MAX * 20];
static lv_color_t buf_2_2[LV_HOR_RES_MAX * 20];
lv_disp_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, LV_HOR_RES_MAX * 20);

/* 方案3:双全屏缓冲,性能最好,内存消耗最大 */
static lv_color_t buf_3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];
static lv_color_t buf_3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX];
lv_disp_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX);

对于RAM有限的MCU,建议使用方案2。

  1. 实现disp_flush函数:
    void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
    {
    int32_t x, y;
    for(y = area->y1; y <= area->y2; y++) {
    for(x = area->x1; x <= area->x2; x++) {
    lcd_draw_point(x, y, color_p->full);
    color_p++;
    }
    }
    lv_disp_flush_ready(disp_drv);
    }

注意:每次写入一个像素后,color_p指针需要自增,否则会一直写同一个颜色。如果LCD驱动支持区域填充,建议改为批量写入,能明显提高刷新速度。

六、移植触摸驱动(可选)

如果需要触摸功能,在lv_port_indev.c中实现坐标读取:

bool touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
uint16_t x, y;
bool pressed = touch_get_coord(&x, &y);
if(pressed) {
>七、将LVGL加入工程

7.1 添加源文件

在IDE中添加以下目录中的所有.c文件:

  • lvgl/src/
  • lvgl_port/
  • lv_demos/(如果需要Demo)

7.2 添加头文件路径

编译器搜索路径需包含:

  • lvgl/
  • lvgl/src/
  • lvgl_port/
  • lv_demos/
  • 工程根目录(lv_conf.h所在位置)

7.3 编译器优化选项

在使用MounRiver Studio时,默认的-O2优化可能导致动画异常。建议改为-Og,并勾选-fno-strict-aliasing。位置在项目属性的C/C++ Build → Settings → Optimization中。

八、主程序编写

8.1 初始化顺序

#include “lvgl.h”
#include “lv_port_disp.h”
#include “lv_port_indev.h”

int main(void)
{
SystemClock_Config();
lcd_init();
touch_init(); // 可选
lv_init();
lv_port_disp_init();
lv_port_indev_init(); // 可选
lv_demo_widgets(); // 或者自定义UI
while(1) {
lv_task_handler();
delay_ms(5);
}
}

8.2 提供心跳

LVGL需要周期性的时钟中断来驱动动画和定时器。可以在定时器中断中调用:

void TIMx_IRQHandler(void)
{
lv_tick_inc(1); // 1ms一次
}

九、编译与调试

常见问题

  • 找不到 lv_conf.h:检查头文件路径是否包含工程根目录,或添加宏LV_CONF_INCLUDE_SIMPLE
  • 内存不足:减小LV_MEM_SIZE或缓冲区大小。
  • 链接错误:检查是否所有.c文件都已添加。

烧录后如果屏幕正常显示Demo界面,说明移植成功。如果黑屏,建议按以下顺序检查:

  1. disp_flushcolor_p指针是否自增
  2. LCD初始化是否正确
  3. lv_conf.h中的分辨率是否与屏幕匹配
  4. LVGL初始化是否执行完毕

十、一些优化思路

如果界面不够流畅,可以尝试:

  • 使用双部分缓冲代替单缓冲
  • disp_flush中使用区域填充代替逐点绘制
  • 适当降低刷新周期
  • 如有DMA,可用于传输显示数据
  • 使用-Og优化等级,避免-O2引起的动画问题

总结

移植LVGL到RISC-V平台,核心就是实现显示驱动的disp_flush回调,让LVGL能够把绘制数据送到屏幕上。配置好分辨率、颜色深度和内存大小,按正确的顺序初始化,基本就能跑起来。整个过程不算复杂,但细节较多。希望这份记录对你有帮助。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 6:43:58

利用API接口获取商品评论操作指南

一、前置准备 接口选型‌&#xff1a;优先选择对应电商平台官方开放接口&#xff0c;合规性和稳定性最高&#xff0c;避免使用非授权第三方接口。 资质认证‌&#xff1a;注册对应平台开放平台账号&#xff0c;完成个人/企业开发者实名认证&#xff0c;创建应用并提交业务说明申…

作者头像 李华
网站建设 2026/7/10 6:43:47

DC-DC升压转换设计与TPS61170应用详解

1. 项目背景与核心器件选型在电力电子设计中&#xff0c;DC-DC升压转换是常见需求&#xff0c;尤其当需要从低压电源&#xff08;如锂电池或USB端口&#xff09;产生较高工作电压&#xff08;如24V或36V&#xff09;时。本项目采用TI的TPS61170作为核心升压芯片&#xff0c;配合…

作者头像 李华
网站建设 2026/7/10 6:43:22

KNX Secure 全解析:智能楼宇如何守住网络安全底线?

一、智能建筑的隐形风险一栋法兰克福 A 级写字楼曾因未加密的 IP 网关遭攻击&#xff0c;黑客远程关闭整栋楼的暖通与照明&#xff0c;直接损失超 10 万欧元。智能建筑越互联&#xff0c;攻击面越大——照明、HVAC、门禁&#xff0c;每一个子系统都是潜在入口。KNX Secure 正是…

作者头像 李华
网站建设 2026/7/10 6:43:20

逆向电商平台Anti-Content参数:从定位到环境补全的完整实战指南

1. 项目概述&#xff1a;逆向某多Anti-Content参数的核心价值最近在跟一些做数据分析和风控研究的朋友交流时&#xff0c;频繁听到一个词&#xff1a;“Anti-Content”。尤其是在涉及某头部电商平台&#xff08;下文我们以“某多”代称&#xff09;的接口请求时&#xff0c;这个…

作者头像 李华
网站建设 2026/7/10 6:41:25

基于STM32单片机金属探测硬币识别涡流传感器盲盒识别设计DIY189

本系统由STM32F103C8T6单片机核心板、1.44寸TFT彩屏、JR6001语音播报电路、金属探测涡流传感器、独立按键电路及电源组成。【1】本设计单片机实时采集金属探测涡流传感器频率值&#xff0c;根据不同大小金属靠近金属探测涡流传感器对磁场影响产生的频率值变化&#xff0c;来进行…

作者头像 李华