基于 DM 的 LVGL 演示方案
在 Luban-Lite SDK 中集成了一套基于 Dynamic Module (DM) 架构的 LVGL 示例程序,旨在为开发者提供一个基础的应用框架模板,便于快速构建和扩展图形用户界面应用。
本方案包含以下核心模块:
- DM Daemon 守护进程
- 函数符号导出表
- LVGL UI 示例程序
- 资源打包策略
DM Daemon 守护进程
该模块实现类似 Unix/ Linux 系统中的后台服务功能,主要承担双重角色:
- 运行时模式:系统运行时,独立执行预编译的 DM 模块(默认路径为
/data/hello.mo) - 编译时集成:将 LVGL 框架静态链接至 RTOS 内核镜像
实现代码位于packages/artinchip/lvgl-ui/aic_demo/dm_daemon/dm_daemon.c 文件。
关键代码片段如下所示:
#include<rtthread.h>
#include "lvgl.h"
#include "dfs_posix.h"
#include <sys/errno.h>
#include <unistd.h>
#include <ymodem.h>
#define DM_EXECUTABLE_FILE "/data/hello.mo" // DM 可执行文件默认路径
int dm_daemon(void) {
if (access(DM_EXECUTABLE_FILE, F_OK) == 0) {
printf("Detected file: '%s'\n", DM_EXECUTABLE_FILE);
system(DM_EXECUTABLE_FILE); // 启动 DM 模块
} else {
printf("Error: File '%s' not found!\n", DM_EXECUTABLE_FILE);
}
return 0;
}
函数符号导出机制
通过专用文件 dm_export.c 集中管理需暴露给外部调用的 API,确保符号可见性与版本控制。支持以下三类接口导出:
| 类别 | 示例函数 | 说明 |
|---|---|---|
| LVGL API | lv_obj_remove_flag,
lv_init() | LittlevGL 核心接口 |
| ArtInChip HAL | lvgl_thread_init,
aic_mdelay() | 硬件抽象层适配函数 |
| RT-Thread OS | rt_tick_get_millisecond | 实时操作系统服务 |
关键代码片段如下所示:
#include <rtthread.h>
#include <lvgl.h>
#include <rtm.h>
#include <stdint.h>
#include "aic_common.h"
// LVGL API
RTM_EXPORT(lv_obj_remove_flag);
RTM_EXPORT(lv_obj_add_event_cb);
RTM_EXPORT(lv_obj_align);
RTM_EXPORT(lv_screen_active);
RTM_EXPORT(lv_button_create);
RTM_EXPORT(lv_display_get_screen_active);
RTM_EXPORT(lv_display_get_default);
RTM_EXPORT(lv_event_get_code);
RTM_EXPORT(lv_log_register_print_cb);
RTM_EXPORT(lv_tick_set_cb);
RTM_EXPORT(lv_init);
RTM_EXPORT(lv_timer_handler);
RTM_EXPORT(lv_label_create);
RTM_EXPORT(lv_label_set_text);
RTM_EXPORT(lv_obj_center);
RTM_EXPORT(lv_obj_set_height);
RTM_EXPORT(lv_obj_add_flag);
// ArtInChip API
extern int lvgl_thread_init(void);
RTM_EXPORT(lvgl_thread_init);
extern void lv_port_disp_init(void);
RTM_EXPORT(lv_port_disp_init);
extern void lv_port_indev_init(void);
RTM_EXPORT(lv_port_indev_init);
extern void lv_user_gui_init(void);
RTM_EXPORT(lv_user_gui_init);
extern void lv_wait_fs_mounted(void);
RTM_EXPORT(lv_wait_fs_mounted);
extern void aic_mdelay(u32 ms);
RTM_EXPORT(aic_mdelay);
// RT-Thread API
RTM_EXPORT(rt_tick_get_millisecond);
extern void ulog_output(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, ...);
RTM_EXPORT(ulog_output);
extern struct dfs_filesystem *dfs_filesystem_lookup(const char *path);
RTM_EXPORT(dfs_filesystem_lookup);
开发者可根据实际需求在此文件中追加新的导出项。
UI 示例程序
提供完整的交互式界面开发样板:
- 项目路径: packages/artinchip/aic-dm-apps/hello
- 主入口文件:main.c,负责初始化 LVGL 组件及事件循环
- 页面逻辑实现: ui_button.c,定义按钮控件的行为与渲染逻辑
该示例展示了如何通过标准 API 创建可响应用户输入的基础控件。
资源管理策略
采用分区存储方案优化系统资源利用率:
| 类型 | 目标目录 | 适用场景 |
|---|---|---|
| 只读数据 | /rodata/ | 静态常量、配置文件等 |
| 读写型数据 | /data/ | 运行时生成的内容 |
打包脚本 packages/artinchip/lvgl-ui/aic_demo/dm_daemon/SConscript:
构建脚本示例
from building import *
import os
current_dir = GetCurrentDir()
build_group = []
source_files = Glob('*.c')
include_paths = [current_dir]
for entry in os.listdir(current_dir):
subpath = os.path.join(current_dir, entry)
if os.path.isfile(os.path.join(subpath, 'SConscript')):
build_group += SConscript(os.path.join(entry, 'SConscript'))
installation_rules = [
('assets/', 'rodata/'), # 资源文件安装到只读分区
('bin/', 'data/') # 二进制文件安装到可写分区
]
build_group += DefineGroup(
name='LVGL-port',
sources=source_files,
dependencies=['AIC_LVGL_DM_DAEMON'],
CPPPATH=include_paths,
INSTALL=installation_rules
)
Return('group')
配置和部署流程
- 在内核配置项中,启用 RT-Thread
的关键特性支持:
Rt-Thread options ---> RT-Thread Components ---> C/C++ and POSIX layer ---> POSIX (Portable Operating System Interface) layer ---> [*] Enable POSIX file system and I/O [*] Enable dynamic module APIs, dlopen()/dlsym()/dlclose() etc - 在应用选项中,打开如下配置:
Application options ---> ArtInChip LVGL demo ---> select LVGL demo (LVGL demo with dm daemon function) - 在 SDK 根目录编译一次,确保 Dynamic Module 配置生效,以及需要用到的函数已经被导出。
- 切换至 packages/artinchip/aic-dm-apps 目录,运行下列命令对 DM
模块进行编译:
scons --app=hello编译后会生成 packages/artinchip/aic-dm-apps/hello/hello.mo 文件。
- 选择以下任意方式之一将 hello.mo 文件部署到系统中:
- 手动拷贝至设备的 /data 目录并执行。
- 将 hello.mo 放入 packages/artinchip/lvgl-ui/aic_demo/dm_daemon/bin/,重新编译 SDK 并烧录固件。
-
执行
dm_daemon或直接运行 /data/hello.mo 后呈现如下界面:
