当前位置: 首页 > news >正文

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能够把绘制数据送到屏幕上。配置好分辨率、颜色深度和内存大小,按正确的顺序初始化,基本就能跑起来。整个过程不算复杂,但细节较多。希望这份记录对你有帮助。

http://www.cnnetsun.cn/news/3257536.html

相关文章:

  • 利用API接口获取商品评论操作指南
  • DC-DC升压转换设计与TPS61170应用详解
  • KNX Secure 全解析:智能楼宇如何守住网络安全底线?
  • 逆向电商平台Anti-Content参数:从定位到环境补全的完整实战指南
  • 机器学习实战:从零掌握集成学习(RF/XGBoost/GBDT/AdaBoost)—— 附泰坦尼克号、红酒分类、加州房价全流程解析
  • 基于STM32单片机金属探测硬币识别涡流传感器盲盒识别设计DIY189
  • DisplayPort 1.4 接口引脚定义详解:20针脚功能与5根GND实测分析
  • 齐纳二极管 1N4461 基准电压电路设计:限流电阻 3 步计算法与 1mA~210mA 电流范围验证
  • Unity URP-PSX插件:用现代管线精准复刻PS1复古图形风格
  • CAD Exchanger SDK 3.24.0 Web Toolkit 3 项新功能解析与实战应用
  • 四足机器人腿部结构选型指南:3种仿生构型与5种自由度配置对比
  • Vibe-Trading:基于Agent架构的Python量化交易框架实战解析
  • Python环境配置指南:Anaconda与VS Code高效开发环境搭建
  • Instatic CMS:基于Bun和SQLite的轻量级内容管理解决方案
  • 【大数据课程设计/毕业设计】Django 架构下基于协同过滤的酒店住宿推荐平台的设计与实现 基于多维特征匹配的经济型酒店智能推荐系统【附源码、数据库、万字文档】
  • Meta智能眼镜面部识别技术解析与隐私保护实践
  • DHT11 单总线通信时序解析:STM32 HAL 库实现 40us 级精准延时方案
  • SolidWorks 2026 安装部署全指南:系统级配置与许可实战
  • ArcGIS API for Python 2.4.3 实战:5步自动化生成城市热力图与PDF报告
  • Mac mini 4 DFU刷机为何不能用Windows虚拟机
  • 抖音批量下载终极指南:如何免费高效获取无水印视频素材
  • ExifToolGui完整指南:3分钟学会免费批量管理照片元数据
  • 还在翻分带表?这个“辅助计算”功能,让CAD漂移数据精准归位!
  • 逸模智造・BIM 效能专栏四:一体化渲染交付,图算视协同出成果
  • 毕业设计项目 基于大数据的K-means广告效果分析
  • 写字楼场景自动售货机:选品和运营的实战指南~YH
  • so101 机器人遥操作、数据集采集
  • 支付之门03:一张图看懂中国支付清算生态,谁在管钱、谁在通路、谁在服务
  • MV-Forcing:基于4D几何桥接的多视角视频生成框架解析
  • Upload-labs靶场通关指南:21种文件上传漏洞实战解析与防御