Zephyr下使用LVGL指南

Creative Commons
本作品采用知识共享署名

本文简要说明Zephyr下如何配置使用LVGL。

Zephyr将LVGL做为外部模块纳入使用,在开发Zephyr应用时,不需要再对lvgl进行驱动的移植,只用进行简单的配置就可以让lvgl使用Zephyr支持的显示和输入驱动。Zephyr主要做了下面三件事来达成该目的:

  • 显示: 使用zephyr display驱动支持的设备作为lvgl的显示设备
  • 输入:使用zephyr kscan驱动支持的设备作为lvgl的输入设备
  • 配置:将lvgl的配置项转化为zephyr的Kconfig配置项
    本文不涉及LVGL实现GUI的说明,本文针对上面三个方面说明如何在Zephyr下启用LVGL:

显示

Zephyr在移植lvgl显示部分的时候,是以自己标准的display接口zephyr\include\drivers\display.h进行移植的,因此只要是Zephyr display driver支持的设备都可以配置作为lvgl的物理显示器。
例如有一片ST7789V的SPI屏,屏的分辨率为240*240, 屏所支持的色彩深度为16bit,通过下面配置就可以让LVGL使用该屏:

  1. 设备树指定屏的硬件信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    &lpspi4 {
    status = "okay";
    pcs-sck-delay = <1>;
    sck-pcs-delay = <1>;
    transfer-delay = <1>;
    /* Sitronix ST7789V LCD */
    st7789v: st7789v@1 {
    compatible = "sitronix,st7789v";
    reg = <1>;
    spi-max-frequency = <30000000>; /* 30MHz */
    label = "ST7789V";
    cmd-data-gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
    reset-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
    width = <240>;
    height = <240>;
    x-offset = <0>;
    y-offset = <0>;
    vcom = <0x19>;
    gctrl = <0x35>;
    vrhs = <0x12>;
    vdvs = <0x20>;
    mdac = <0x00>;
    gamma = <0x01>;
    colmod = <0x05>;
    lcm = <0x2c>;
    porch-param = [0c 0c 00 33 33];
    cmd2en-param = [5a 69 02 01];
    pwctrl1-param = [a4 a1];
    pvgam-param = [D0 04 0D 11 13 2B 3F 54 4C 18 0D 0B 1F 23];
    nvgam-param = [D0 04 0C 11 13 2C 3F 44 51 2F 1F 1F 20 23];
    ram-param = [00 F0];
    rgb-param = [CD 08 14];
    };
    };
  2. 配置使用该屏
    通过简单的配置LVGL就会将该屏作为自己的显示设备,各项配置注释如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 启用display驱动
    CONFIG_DISPLAY=y

    # 指定lvgl使用的显示设备,使用的是设备树中屏的lable ST7789V
    CONFIG_LVGL_DISPLAY_DEV_NAME="ST7789V"

    # 指定LVGL支持的最大分辨率,物理屏的最大分辨率应该小于该分辨率
    CONFIG_LVGL_HOR_RES_MAX=240
    CONFIG_LVGL_VER_RES_MAX=240

    # 指定屏的色彩深度
    CONFIG_LVGL_COLOR_DEPTH_16=y

输入

对lvgl的输入Zephyr原生只移植了KSCAN,KSCAN的驱动的关键信息为行,列,按压,对应到lvgl的Pointer输入类型。KSCAN比较适合触摸屏,鼠标等抽象,极端情况下也可以用来抽象阵列键盘。Zephyr目前KSCAN支持的驱动很少,大多数情况下新硬件都需要自己添加。KSCAN的驱动模型和添加方法请参考Zephyr上添加触屏驱动。这里也用该文章中添加的gt917s驱动来说明如何配置LVGL使用KSCAN。

  1. 设备树指定输入设备硬件信息
1
2
3
4
5
6
7
8
9
10
11
12
13
&i2c1 {                 //gt917s挂在i2c1下
status = "okay";

gt9x@14 {
compatible = "coodix,gt9x";
reg = <0x14>;
label = "GT9X";
width = <800>;
height = <480>;
int-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
};
};
  1. 配置使用该KSCAN设备
    1
    2
    3
    4
    5
    6
    7
    8
    CONFIG_KSCAN=y                  #enable kscan
    CONFIG_KSCAN_GT9X=y #使用GT917S驱动
    CONFIG_KSCAN_INIT_PRIORITY=55 #驱动初始化优先级
    CONFIG_KSCAN_GT9X_PERIOD=10 #轮询GT917S的时间间隔,单位为ms
    #CONFIG_KSCAN_GT9X_INTERRUPT=y #配置该项后将只用中断通知接收按键,不再进行轮询

    CONFIG_LVGL_POINTER_KSCAN=y #指定LVGL使用KSCAN做为输入
    CONFIG_LVGL_POINTER_KSCAN_DEV_NAME="GT9X" #指定lvgl使用的输入设备,使用的是设备树中触摸屏的lable GT9X

Zephyr原生只对lvgl支持kscan,而kscan这种抽象只能支持嵌入式设备中很少一部分的输入设备。我们可以通在应用中为lvgl添加输入设备,让Zephyr下的lvgl支持更多类型的数据如设备,这部分内容将在下一篇文章中介绍。

配置项

LVGL是一个配置项极强的gui,通过在lv_conf.h进行配置可以精简不使用的组件,调整lvgl的特性。Zephyr将lv_conf.h和Kconfig结合起来,通过Kconfig的配置可以自动调整lv_conf.h达到对LVGL的裁剪和配置。

配置转换方式

Zephyr中将Kconfig转换为lv_conf.h内的配置宏,例如:

1
#define LV_USE_BTN IS_ENABLED(CONFIG_LVGL_USE_BTN)

配置项简介

Zephyr中将lvgl的配置分为了10各部分,每个部分的配置项都可以在zephyr\lib\gui\lvgl中的Kconfig文件找到:

1
2
3
4
5
6
7
8
9
10
├── Kconfig.debug
├── Kconfig.feature
├── Kconfig.fonts
├── Kconfig.graphical
├── Kconfig.image
├── Kconfig.input
├── Kconfig.memory
├── Kconfig.objects
├── Kconfig.text
├── Kconfig.themes

  • 调试
  • 特性
  • 字体
  • 图形显示
  • 图像
  • 输入
  • 内存
  • 物件
  • 文本
  • 主题

本文只做简单介绍配置项和注意事项,说明具体的配置项和LVGL本身关系很大,这里不进行罗列说明,需要了解细节可以对比查看上述10个文件和lv_conf.h。

调试

Kconfig.debug中保存了和LVGL调试相关的配置项,例如lvgl提供的各种调试断言,一般情况下我们并不会使用

特性

Kconfig.feature中保存了和LVGL特性相关的配置项,例如使用过渡动画,物件阴影,矩形边框等。值得注意的是在lvgl编程过程中代码使用了某个特性,但未配置,这在编译期不会报错。例如我之前使用MATERIAL主题,选中的焦点应该有边框,但实际屏幕上缺显示不出来,最后才发现是CONFIG_LVGL_USE_OUTLINE=y没配置。

字体

Kconfig.fonts中保存了和LVGL字体相关的配置项,可以配置字体是否压缩,render模式,以及选择的内置字体。

图形显示

Kconfig.graphical中保存了和图形显示相关的配置项,指定显示的设备名,最大支持的分辨率,色彩深度,DPI,透明色等等

图像

Kconfig.image中保存了和图形显示相关的配置项,可以指定lvgl对图像支持的特性

输入

Kconfig.input中保存了和输入相关的配置项, 指定输入设备的方式,输入设备名,读输入设备的周期,长按/repeat的时间阈值等。

内存

Kconfig.memory中保存了和内存相关的配置项,指定每个像素的字节大小,LVGL使用Pool的配置,VDB大小,是否使用双buffer,fb的分配方式等。

物件

Kconfig.objects中保存了和物件相关的配置项,指定按键,进度条,文本框等控件。

文本

Kconfig.text中保存了和文本相关的配置项,指定文本编码格式,换行长度, BIDI特性等

主题

Kconfig.themes中保存了和主题相关的配置项,指定各种主题,主题的字体,样式等等

配置建议

lvgl的配置项众多,不一定能能记全,上面的Kconfig文件也只是能看出我们可以按照下面步骤在Zephyr中对lvgl进行配置:

  1. 不进行任何配置,直接进行lvgl编程
  2. 编程完毕后进行编译,查看报错信息里面会提示缺失的lvgl文件和错误代码片段(通常是缺少某部分内容)
  3. 根据缺失的内容可以确认LVGL的配置选项LV_XXXX
  4. 根据你需要的lvgl特性,确认LV_XXXX配置项
  5. 在zephyr\lib\gui\lvgl\lv_conf.h中搜索LV_XXXX, 就可以找到对应的CONFIG_LVGL_XXX,将其加入到prj.conf
    下面是一个Zephyr lvgl应用的示例配置文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    CONFIG_DISPLAY=y
    CONFIG_DISPLAY_LOG_LEVEL_ERR=y

    CONFIG_LVGL=y

    CONFIG_LVGL_DISPLAY_DEV_NAME="ST7789V"
    CONFIG_LVGL_HOR_RES_MAX=240
    CONFIG_LVGL_VER_RES_MAX=240
    CONFIG_LVGL_DPI=100
    CONFIG_LVGL_COLOR_DEPTH_16=y
    CONFIG_LVGL_COLOR_16_SWAP=y

    CONFIG_LVGL_USE_LABEL=y
    CONFIG_LVGL_USE_CONT=y
    CONFIG_LVGL_USE_BTN=y
    CONFIG_LVGL_USE_BAR=y
    CONFIG_LVGL_USE_SLIDER=y
    CONFIG_LVGL_USE_GROUP=y
    CONFIG_LVGL_USE_TEXTAREA=y
    CONFIG_LVGL_USE_MSGBOX=y
    CONFIG_LVGL_USE_SWITCH=y
    CONFIG_LVGL_USE_LIST=y
    CONFIG_LVGL_USE_PAGE=y
    CONFIG_LVGL_USE_TABVIEW=y
    CONFIG_LVGL_USE_KEYBOARD=y
    CONFIG_LVGL_USE_CHECKBOX=y
    CONFIG_LVGL_USE_TABLE=y
    CONFIG_LVGL_USE_BTNMATRIX=y
    CONFIG_LVGL_USE_SPINBOX=y
    CONFIG_LVGL_USE_ROLLER=y
    CONFIG_LVGL_USE_DROPDOWN=y
    CONFIG_LVGL_USE_IMG=y

    CONFIG_LVGL_USE_OUTLINE=y
    CONFIG_LVGL_ANTIALIAS=y

    CONFIG_LVGL_USE_THEME_MATERIAL=y
    CONFIG_LVGL_THEME_MATERIAL_LIGHT=y

    CONFIG_LVGL_USE_FONT_COMPRESSED=y
    CONFIG_LVGL_FONT_MONTSERRAT_12=y
    CONFIG_LVGL_FONT_MONTSERRAT_14=y
    CONFIG_LVGL_FONT_MONTSERRAT_16=y
    CONFIG_LVGL_FONT_MONTSERRAT_18=y

LVGL task handler

Zephyr对lvgl的各方面都做了很完整的移植,但偏偏没有开thread定期呼叫lv_task_handler,因此我们需要开一个thread定期执行lv_task_handler,例如我们可以放到main内,让其在main thread中执行

1
2
3
4
5
6
7
8
9
10
11
12
void main(void)

//app init
app(indev);
lv_task_handler();
display_blanking_off(display_dev);

while (1) {
lv_task_handler();
k_sleep(K_MSEC(10));
}
}

由于lv_task_handler是lvgl的推动引擎,lvgl的各项任务均在该handler内执行,也许是基于系统性能的考虑Zephyr将是否用thread,用thread的优先级等特性交给用户处理,以达到更大的灵活性。