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
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];
};
};配置使用该屏
通过简单的配置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 | &i2c1 { //gt917s挂在i2c1下 |
- 配置使用该KSCAN设备
1
2
3
4
5
6
7
8CONFIG_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进行配置:
- 不进行任何配置,直接进行lvgl编程
- 编程完毕后进行编译,查看报错信息里面会提示缺失的lvgl文件和错误代码片段(通常是缺少某部分内容)
- 根据缺失的内容可以确认LVGL的配置选项LV_XXXX
- 根据你需要的lvgl特性,确认LV_XXXX配置项
- 在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
44CONFIG_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
12void 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的优先级等特性交给用户处理,以达到更大的灵活性。