Edit online

基于 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 APIlv_obj_remove_flag, lv_init()LittlevGL 核心接口
ArtInChip HALlvgl_thread_init, aic_mdelay()硬件抽象层适配函数
RT-Thread OSrt_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')

配置和部署流程

  1. 在内核配置项中,启用 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
  2. 在应用选项中,打开如下配置:
    Application options  --->
        ArtInChip LVGL demo  --->
            select LVGL demo (LVGL demo with dm daemon function)
  3. 在 SDK 根目录编译一次,确保 Dynamic Module 配置生效,以及需要用到的函数已经被导出。
  4. 切换至 packages/artinchip/aic-dm-apps 目录,运行下列命令对 DM 模块进行编译:
    scons --app=hello

    编译后会生成 packages/artinchip/aic-dm-apps/hello/hello.mo 文件。

  5. 选择以下任意方式之一将 hello.mo 文件部署到系统中:
    • 手动拷贝至设备的 /data 目录并执行。
    • hello.mo 放入 packages/artinchip/lvgl-ui/aic_demo/dm_daemon/bin/,重新编译 SDK 并烧录固件。
  6. 执行 dm_daemon 或直接运行 /data/hello.mo 后呈现如下界面: