K230 GUI实战 - LVGL移植教程#

K230 GUI实战#

LVGL是流行的免费开源嵌入式图形库,可以用于嵌入式系统的图形用户界面(GUI)开发。

硬件环境#

  • K230-USIP-LP3-EVB-V1.1

  • 配套的LCD模组

概述#

k230使用DRM作为显示驱动,DRM(Direct Rendering Manager) 是 Linux 内核中的一个子系统,相比过时的Framebuffer 可以支持复杂的 GPU 操作,如硬件加速的图形渲染。lvgl可以基于libdrm提供的接口进行GUI的绘制。

SDK中已经移植好lvgl组件,且默认编译了一个可以运行的demo,位于/usr/bin/lvgl_demo_widgets。开机后在小核linux终端输入命令lvgl_demo_widgets回车即可体验。

lvgl源码位置#

SDK中已经包含移植好的lvgl,路径位于src/little/buildroot-ext/package/lvgl。在SDK的buildroot编译过程中会将源码放置于目录output/k230_evb_defconfig/little/buildroot-ext/build/lvgl-v8.3.7下,该目录包含了从github拉取的lvgl源码包以及前面所说的src路径下的移植文件。目录结构如下:

.
├── lv_conf.h
├── lv_drivers
│   ├── display
│      ├── drm.c
│      └── drm.h
│   ├── indev
│      ├── AD_touch.c
│      ├── AD_touch.h
│      ├── evdev.c
│      ├── evdev.h
│      ├── keyboard.h
│      ├── libinput.c
│      ├── libinput_drv.h
│      ├── mouse.h
│      └── mousewheel.h
│   └── lv_drivers.mk
├── lv_drv_conf.h
├── main.c
├── Makefile
└── mouse_cursor_icon.c

lvgl的DRM驱动#

linux内核中DRM驱动加载成功后会出现以下节点/dev/dri/card0

DRM配置相关#

在头文件src/little/buildroot-ext/package/lvgl/port_src/lv_drv_conf.h

  • 配置宏定义define USE_DRM 1来使能DRM显示驱动

  • 配置宏定义define DRM_CARD  "/dev/dri/card0"指定DRM驱动节点

DRM驱动源码具体介绍#

lvgl的drm驱动程序位于src/little/buildroot-ext/package/lvgl/port_src/lv_drivers/display/drm.c。 对DRM的操作需要先open该文件节点。
lvgl使用中主要用到以下几个函数:

  • drm_init() drm初始化。

  • drm_get_sizes() 获取显示器分辨率信息。

  • drm_flush() 显示绘制回调接口。

drm初始化过程中会自动获取DRM的资源,包括获知connect id, plane id, crtc id等,会根据配置文件中选定的颜色格式自动匹配对应支持的plane。

该drm驱动默认开启了双buffer,但目前在没有硬件加速的情况下,双缓冲刷新率低,可以注释掉下面代码以单缓冲方式刷新,显示效果会更好:

void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
    ...
 if (!drm_dev.cur_bufs[0])
  drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1];
 else
  drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
  drm_dev.cur_bufs[0] = fbuf;
    ...
}

lvgl的使用#

lvgl的主程序文件位于src/little/buildroot-ext/package/lvgl/port_src/main.c

lvgl配置相关#

lvgl配置文件位于:src/little/buildroot-ext/package/lvgl/port_src/lv_conf.h

以下是几个常用的配置项:

  • #define LV_COLOR_DEPTH 32 设置颜色深度

  • #define LV_COLOR_SCREEN_TRANSP 1 设置屏幕透明

  • #define LV_DPI_DEF 300 设置屏幕DPI

  • #define LV_USE_PERF_MONITOR 1 显示fps以及cpu占用率,用于调试

  • #define LV_USE_MEM_MONITOR 1 显示内存占用,用于调试

  • #define LV_USE_DEMO_WIDGETS  1 启用lvgl widgets demo

lvgl使用的主要步骤#

  1. LVGL初始化:

    lv_init();

  2. 显示驱动初始化:

    drm_init();
    drm_get_sizes(&lcd_w, &lcd_h, &lcd_dpi);
    printf("lcd w,h,dpi:%d,%d,%d \n", lcd_w, lcd_h, lcd_dpi);
    
    uint32_t draw_buf_size = lcd_w * lcd_h * sizeof(lv_color_t) / 4; /*1/4 screen sized buffer has the same performance */
    static lv_disp_draw_buf_t disp_buf;
    lv_color_t *buf_2_1 = malloc(draw_buf_size);
    lv_color_t *buf_2_2 = malloc(draw_buf_size);
    lv_disp_draw_buf_init(&disp_buf, buf_2_1, buf_2_2, draw_buf_size);
    
    /*Initialize and register a display driver*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.draw_buf   = &disp_buf;
    disp_drv.flush_cb   = drm_flush;
    disp_drv.hor_res    = lcd_w;
    disp_drv.ver_res    = lcd_h;
    disp_drv.screen_transp = 1;
    lv_disp_drv_register(&disp_drv);
    
  3. 触摸驱动:

    evdev_init();
    static lv_indev_drv_t indev_drv_1;
    lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
    indev_drv_1.type = LV_INDEV_TYPE_POINTER;
    
    /*This function will be called periodically (by the library) to get the mouse position and state*/
    indev_drv_1.read_cb = evdev_read;
    lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
    
  4. demo例程:

    lv_demo_widgets();

关于lvgl更详细的用法请参考lvgl官网:https://lvgl.io,API文档以及例程:https://docs.lvgl.io/8.3/index.html

也可以使用lvgl的拖放式UI编辑器SquareLine Studio来简化开发:https://squareline.io

编译#

在SDK根目录下执行make默认全部编译。

运行lv_demo_widgets#

lvgl_demo_widgets

执行完上述命令,会在LCD屏幕上显示配置界面,可以通过触摸屏进行相关配置,具体如下所示:

显示内容

当然lvgl应用程序开发也可以作为一个独立项目而不是在SDK中进行编译,可以参考https://github.com/lvgl/lv_port_linux_frame_buffer项目将SDK中的移植文件替换进去,然后配置K230的交叉编译工具链以及对应libdrm引用即可。