前言
之前做项目的时候有了解到LVGL这个开源的gui库,趁着假期就想着把它移植到自己的开发板上看看能不能正常跑起来。虽说不难,但也花了一些功夫,因此也在这里做下总结。
一、LVGL是什么?
LVGL,全称Light and Versatile Graphics Library,以下是官网上的介绍。
LVGL is an open-source graphics library providing everything you need to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint.
翻译过来就是说,LVGL是一个开源的图形库,提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素、漂亮的视觉效果和低内存占用。
官网地址
二、LVGL的移植
1.库下载
前面介绍过,LVGL是一个开源的图形库,因此,我们可以在github上面找到它的开源库。下面是它的地址:
LVGL核心库
lvgl_drivers库
下载后,我们可以得到以下两个tar包
依次解压缩并重新命名,最后我们得到的文件如下:
到这里我们的准备工作都做好了,下面就可以正式开始LVGL图形库的移植了。
2.LVGL核心库配置修改
首先,我们先进入到lvgl目录,在这个目录下,可以看到有一个lv_conf_template.h模板,我们复制一份这个.h文件。
将copy的lv_conf.h文件中的#if 0 改为#if 1
接下来的一些配置需要根据板子的实际情况去修改
/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX (480) //屏幕水平宽度
#define LV_VER_RES_MAX (272) //屏幕水平高度
/* Color depth:
* - 1: 1 byte per pixel
* - 8: RGB332
* - 16: RGB565
* - 32: ARGB8888
*/
#define LV_COLOR_DEPTH 32 //LCD 屏幕的像素深度
#define LV_USE_GPU 0 //这里根据实际情况配置,一般置0
下面这几个可以不做改动
#define LV_USE_PERF_MONITOR 0 //右下角cpu信息输出。测试可以打开看下
# define LV_MEM_SIZE (32U * 1024U) //这里默认的是32K 用作lvgl的动态内存分配。可以根据实际情况修改,但是要大于等于2KB
#define LV_DISP_DEF_REFR_PERIOD 30 //刷新周期 30ms 就是刷新速率问题,看性能设置吧。
#define LV_INDEV_DEF_READ_PERIOD 30//输入设备的扫描时间,就是轮询按键的时间。默认30ms。
#define LV_USE_FILESYSTEM 1 //文件系统不用也可以给置0了
#define LV_USE_DEBUG 1 //debug信息输出可关闭
3.LVGL驱动库配置修改
在lv_drivers目录下,同样有一个lv_drv_conf_template.h配置模板,我们先copy一份出来。
将copy的lv_drv_conf.h文件中的#if 0 改为#if 1
/*-----------------------------------------
* Linux frame buffer device (/dev/fbx)
*-----------------------------------------*/
#ifndef USE_FBDEV
# define USE_FBDEV 1
#endif
#if USE_FBDEV
# define FBDEV_PATH "/dev/fb0" //这里需要确认是否是自己的fb
#endif
到这里,配置修改已经差不多完成了,接下来,就是编译工作了。
4.编译LVGL
我们回到lvgl的根目录,即存放lvgl和lv_drivers文件夹的目录下编写Makefile文件
Makefile:
CC := arm-none-linux-gnueabi-gcc //这里配置好交叉编译器
RM := rm
MV := mv
MKDIR := mkdir
CUR_PATH=$(shell pwd)
LVGL_DIR = $(CUR_PATH)
LVGL_DIR_NAME ?= lvgl
include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
OBJDIR:=./__tmp__
OBJEXT ?= .o
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
SRC = $(ASRCS) $(CSRCS)
OBJ = $(AOBJS) $(COBJS)
CFLAGS:=-g -Wall -std=c99 -I$(LVGL_DIR)/lvgl -I$(LVGL_DIR)/lv_drivers \
-DLV_CONF_INCLUDE_SIMPLE -DLV_LVGL_H_INCLUDE_SIMPLE
.PHONY: all
.DEFAULT: all
all: $(OBJ)
$(MKDIR) $(OBJDIR) -p
$(MV) $(OBJ) $(OBJDIR)
clean:
$(RM) $(OBJDIR) -rf
make all之后,我们可以在该目录下看到生成了一个__tmp__文件,里面存放的是我们所需要的编译好的目标文件,接下来,我们可以编写demo来测试。
三、编写demo测试
main.c
#include "header.h"
/* =========================demo========================== */
static lv_obj_t *label;
static void video_disp_window()
{
lv_obj_t * this_win = lv_cont_create(lv_scr_act(), NULL);
lv_obj_set_size(this_win, LV_HOR_RES, LV_VER_RES);
lv_obj_t *btn = lv_btn_create(this_win, NULL);
label = lv_label_create(btn, NULL);
lv_label_set_text(label, "hello world");
}
/* =========================demo========================== */
int main(int argc, char *argv[])
{
lv_init(); //lvgl gui初始化
fbdev_init();
static lv_color_t buf[DISP_BUF_SIZE];
static lv_disp_buf_t disp_buf;
/* fb init */
lv_disp_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.buffer = &disp_buf;
disp_drv.flush_cb = fbdev_flush;
lv_disp_drv_register(&disp_drv);
video_disp_window();
while (1)
{
lv_task_handler();
usleep(5000);
}
}
header.h
#ifndef __HEADER_H_
#define __HEADER_H_
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <linux/fb.h>
#include "lvgl.h"
#include "display/fbdev.h"
#include "indev/evdev.h"
#define DISP_BUF_SIZE (100 * LV_HOR_RES_MAX)
/* debug */
#if defined(PLAYER_DEBUG_VER) /* DEBUG_VER */
#define __PLAYER_DEBUG__ 1
#endif
#endif
Makefile:
SRCDIR:=.
OBJDIR:=.
TOP_PATH=$(shell pwd)
CC:=arm-none-linux-gnueabi-gcc
#STRIP:=strip
RM := rm
MV := mv
CD := cd
LVGL_DIR = $(TOP_PATH)/external/lvgl
LVGL_DIR_NAME ?= lvgl
include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
CFLAGS:=-w -O2 -O3 -g0 -std=c99 -I$(LVGL_DIR)/lvgl -I$(LVGL_DIR)/lv_drivers \
-DPLAYER_DEBUG_VER -DLV_CONF_INCLUDE_SIMPLE -DLV_LVGL_H_INCLUDE_SIMPLE
.PHONY: all
.DEFAULT: all
LVGL_OBJDIR:=./external/lvgl/__tmp__
#LVGL_OBJS:=$(wildcard $(LVGL_OBJDIR)/*.o)
OBJDIR:=./__tmp__
SRCS:=$(wildcard $(SRCDIR)/*.c)
OBJS:=$(addprefix $(OBJDIR)/,$(patsubst %.c,%.o,$(SRCS)))
PROGRAM:=player
all: $(LVGL_OBJDIR) $(PROGRAM)
$(LVGL_OBJDIR) :
$(CD) $(LVGL_DIR) && make
$(OBJS) : $(OBJDIR)/%.o : %.c
@if [ ! -d $(dir $@) ] ; then mkdir -v -p $(dir $@) ; fi
@echo compile: $<
$(CC) $(CFLAGS) -c $< -o $@
$(PROGRAM): $(OBJS) $(LVGL_OBJDIR)
$(CC) $(OBJS) $(wildcard $(LVGL_OBJDIR)/*.o) -o $(PROGRAM) -lpthread -static -lm
$(MV) $(PROGRAM) $(OBJDIR)
clean:
$(RM) -rf $(LVGL_OBJDIR)
$(RM) -rf $(OBJDIR)
make all之后,同样在目录下会生成__tmp__文件
将player执行程序拷贝到开发板上运行
运行结果如下:
总结
到这里,整个的移植工作大致已经完成,今天就先说到这,后续研究明白了再对这一块做说明。