Zephyr上ssd1306协同lvgl工作

本文介绍如何在zephyr上配置ssd1306和lvgl,并让二者协同工作.

LittlevGL(lvgl) 是一个开源免费的GUI, zephyr将其作为gui组件。SSD1306是一款单色的OLED屏,只有0.96寸大,分辨率为128*64。 一般情况下我们都是直接对SSD1306进行控制,在其framebuffer上画图需要的东西。但在Zephyr上,我们可用通过lvgl很方便在SSD1306上显示出我需要的内容。本文描述如何在Zephyr上配置ssd1306和lvgl,并基于nrf52832演示lvgl和ssd1306协同工作。

配置SSD1306 链接到标题

ssd1306一般有SPI和I2C接口,这里使用的I2C接口,配置SSD1306很简单只用在设备树中描述SSD1306使用的I2C情况,并在配置文件中启动SSD1306既可

设备树修改 链接到标题

在你板子的dts文件中加入如下内容

&i2c0 {
	status = "okay";
	sda-pin = <5>;
	scl-pin = <4>;
	clock-frequency = <I2C_BITRATE_FAST>;

	ssd1306@3c{
		compatible = "solomon,ssd1306fb";
		reg = <0x3c>;
		label = "SSD1306";
		width = <128>;
		height = <64>;
		segment-offset = <0>;
		page-offset = <0>;
		display-offset = <0>;
		segment-remap;
		com-invdir;
		prechargep = <0x22>;
	};
};

以上内容含义如下:

  • ssd1306使用i2c0,SDA为引脚5, SCK为引脚4
  • I2C通讯速率为400kbps(参考nclude/dt-bindings/i2c/i2c.h)
  • ssd1306的i2c地址为3c
  • ssd1306的lable为SSD1306 (zephyr display drv name,后面配置LVGL display name要用到) 其它ssd1306的参数可以参考dts/bindings/display/solomon,ssd1306fb.yaml,都会被对应的转化为宏在驱动代码ssd1306.c里面体现,这里就不做详细介绍。

配置文件修改 链接到标题

详见注释

# 启用I2C驱动
CONFIG_I2C_NRFX=y
CONFIG_I2C_0=y
CONFIG_I2C=y
# 启用SSD1306驱动
CONFIG_SSD1306=y

# 不兼容SH1106,后面专门解释
CONFIG_SSD1306_SH1106_COMPATIBLE=n

LVGL 链接到标题

zephyr已经针对不同的显示形式用自己的display drv对接了LVGL的显示驱动接口,所以对于LVGL来说基本就是配置好就可以直接使用了

配置 链接到标题

基础配置 链接到标题

要想ssd1306能在lvgl下工作,需要启动lvgl并针对ssd1306的显示特性进行配置

# 启用display drv
CONFIG_DISPLAY=y

# 启用LVGL
CONFIG_LVGL=y

# 根据SSD1306的特性配置 LVGL
CONFIG_LVGL_COLOR_DEPTH_1=y
CONFIG_LVGL_BITS_PER_PIXEL=1
CONFIG_LVGL_HOR_RES=128
CONFIG_LVGL_VER_RES=64
CONFIG_LVGL_THEMES=y
CONFIG_LVGL_THEME_MONO=y
CONFIG_LVGL_DPI=30
CONFIG_LVGL_VDB_SIZE=100

#指定LVGL用的display drv name,和前文dts中ssd1306 lable对应
CONFIG_LVGL_DISPLAY_DEV_NAME="SSD1306"

组件配置 链接到标题

为了最小化image,zephyr默认是关闭所有lvgl组件的,因此要根据需求启用组件

#启用lable
CONFIG_LVGL_OBJ_LABEL=y
CONFIG_LVGL_OBJ_TEXT_AREA=y

#启动button
CONFIG_LVGL_OBJ_CONTAINER=y
CONFIG_LVGL_OBJ_BUTTON=y

#启用bar
CONFIG_LVGL_OBJ_BAR=y
CONFIG_LVGL_ANIMATION=y

#启用UTF8,显示汉字用
CONFIG_LVGL_TXT_ENC_UTF8=y

使用 链接到标题

lvgl的使用不是本文重点,因此这里只列一下测试代码。 在zephyr中一旦配置ssd1306和lvgl,对应的初始化代码就会被打开,不需要手动再写,只用进行主题初始化就可以使用lvgl组件了

//ssd1306是单色屏,因此只能初始化为mono
    lv_theme_mono_init(0 /* hue */,NULL /* use LV_FONT_DEFAULT */);
    lv_theme_set_current( lv_theme_get_mono() );

//lable使用汉字
    LV_FONT_DECLARE(hang)   
	static lv_style_t style1;
    lv_style_copy(&style1, &lv_style_plain);
    style1.text.font = &hang; /*Set the base font whcih is concatenated with the others*/

	title_label  = lv_label_create(lv_scr_act(), NULL);
	lv_obj_set_pos(title_label, 40, 0);
	lv_label_set_style(title_label, LV_LABEL_STYLE_MAIN, &style1);
	lv_label_set_text(title_label, "下载中");       

//lable使用英文
	hello_world_label = lv_label_create(lv_scr_act(), NULL);
	lv_obj_set_pos(hello_world_label, 3, 27);
	lv_label_set_text(hello_world_label, "pc:");

//两个按键
	lv_obj_t * btn_pause = lv_btn_create(lv_scr_act(), NULL);    
	lv_obj_set_pos(btn_pause, 4, 48);
	lv_obj_set_size(btn_pause, 46, 12);             
	lv_obj_t * label_pause = lv_label_create(btn_pause, NULL);       
	lv_label_set_text(label_pause, "pause");             

	lv_obj_t * btn_cancel = lv_btn_create(lv_scr_act(), NULL);    
	lv_obj_set_pos(btn_cancel, 80, 48);
	lv_obj_set_size(btn_cancel, 46, 12);             
	lv_obj_t * label_cancel = lv_label_create(btn_cancel, NULL);       
	lv_label_set_text(label_cancel, "exit");    

//一个bar
	lv_obj_t * bar1 = lv_bar_create(lv_scr_act(), NULL);
	lv_obj_set_pos(bar1, 26, 25);
    lv_obj_set_size(bar1, 80, 12);

//一个变化的lable
    count_label = lv_label_create(lv_scr_act(), NULL);
	lv_obj_set_pos(count_label, 110, 27);

//将屏显打开
    display_dev = device_get_binding(CONFIG_LVGL_DISPLAY_DEV_NAME);
    display_blanking_off(display_dev);

//更新bar和变化的lable
    while (1) {
		if ((count % 100) == 0U) {
			if(count/100<100){
				sprintf(count_str, "%d", count/100U);
				lv_label_set_text(count_label, count_str);
				lv_bar_set_value(bar1, count/100U, LV_ANIM_OFF);
			}			
		}
		lv_task_handler();
		k_sleep(2);
		++count;
	}

以上显示的结果如下 lvgl

其它 链接到标题

驱动 链接到标题

目前zephyr master的code按照前面配置会工作异常,是因为上ssd1306的驱动支援并不完整,只能进行全屏更新,无法对指定显示区域进行更新,因此要进行修改后才能支援lvgl, 详见ssd1306驱动要点最后一个小节, 我已提交PR: https://github.com/zephyrproject-rtos/zephyr/pull/18817, merge后就可以生效了。由于没有SH1106无法对其测试,因此该修改只针对SSD1306有效,这就是为什么要在前面将关闭CONFIG_SSD1306_SH1106_COMPATIBLE的原因。

lvgl的porting 链接到标题

在lvgl外设驱动上zephyr目前只对display和fs进行了对接,porting代码见lib/gui/lvgl ssd1306单色屏的display porting文件是lib/gui/lvgl/lvgl_display_mono.c