目錄
準備腳手架
修改源碼
對接觸摸
測試編譯
測試運行
這一節將以一個已經編寫好的?lvgl
?小游戲?2048
?描述如何將已經編寫完成的?lvgl
?程序移植到開發板上。
準備腳手架
在這之前,我們先準備基礎的 LVGL 腳手架。可以直接從?lv_g2d_test
?里復制過來進行修改即可。
首先我們復制源碼,在?platform/thirdparty/gui/lvgl-8
?源碼文件夾里,把 紅箭頭 所指的?lv_g2d_test
?的源碼作為模板復制到黃箭頭指向的?lv_2048
?文件夾里。
如下圖所示,并清理下?res
?資源文件夾,
同樣的,復制一份引索文件,找到?openwrt/package/thirdparty/gui/lvgl-8
?并把?lv_g2d_test
?復制一份重命名為?lv_2048
?作為我們?2048
?小游戲使用的引索。
并編輯?Makefile
,修改文件名稱,把?lv_g2d_test
?修改為這里的?lv_2048
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/package.mk
include ../sunxifb.mkPKG_NAME:=lv_2048
PKG_VERSION:=8.1.0
PKG_RELEASE:=1PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
SRC_CODE_DIR := $(LICHEE_PLATFORM_DIR)/thirdparty/gui/lvgl-8/$(PKG_NAME)
define Package/$(PKG_NAME)SECTION:=guiSUBMENU:=LittlevglCATEGORY:=GuiDEPENDS:=+LVGL8_USE_SUNXIFB_G2D:libuapi +LVGL8_USE_SUNXIFB_G2D:kmod-sunxi-g2d \+LVGL8_USE_FREETYPE:libfreetypeTITLE:=lvgl 2048
endefPKG_CONFIG_DEPENDS := \CONFIG_LVGL8_USE_SUNXIFB_DOUBLE_BUFFER \CONFIG_LVGL8_USE_SUNXIFB_CACHE \CONFIG_LVGL8_USE_SUNXIFB_G2D \CONFIG_LVGL8_USE_SUNXIFB_G2D_ROTATEdefine Package/$(PKG_NAME)/config
endefdefine Package/$(PKG_NAME)/Default
endefdefine Package/$(PKG_NAME)/descriptiona lvgl 2048 v8.1.0
endefdefine Build/Prepare$(INSTALL_DIR) $(PKG_BUILD_DIR)/$(CP) -r $(SRC_CODE_DIR)/src $(PKG_BUILD_DIR)/$(CP) -r $(SRC_CODE_DIR)/../lvgl $(PKG_BUILD_DIR)/src/$(CP) -r $(SRC_CODE_DIR)/../lv_drivers $(PKG_BUILD_DIR)/src/
endefdefine Build/Configure
endefTARGET_CFLAGS+=-I$(PKG_BUILD_DIR)/srcifeq ($(CONFIG_LVGL8_USE_SUNXIFB_G2D),y)
TARGET_CFLAGS+=-DLV_USE_SUNXIFB_G2D_FILL \-DLV_USE_SUNXIFB_G2D_BLEND \-DLV_USE_SUNXIFB_G2D_BLIT \-DLV_USE_SUNXIFB_G2D_SCALE
endifdefine Build/Compile$(MAKE) -C $(PKG_BUILD_DIR)/src\ARCH="$(TARGET_ARCH)" \AR="$(TARGET_AR)" \CC="$(TARGET_CC)" \CXX="$(TARGET_CXX)" \CFLAGS="$(TARGET_CFLAGS)" \LDFLAGS="$(TARGET_LDFLAGS)" \INSTALL_PREFIX="$(PKG_INSTALL_DIR)" \all
endefdefine Package/$(PKG_NAME)/install$(INSTALL_DIR) $(1)/usr/bin/$(INSTALL_DIR) $(1)/usr/share/lv_2048$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/$(PKG_NAME) $(1)/usr/bin/
endef$(eval $(call BuildPackage,$(PKG_NAME)))
完成腳手架的搭建后,可以?make menuconfig
?里查看是否出現了?lv_2048
?這個選項,選中它。
修改源碼
第二步是修改源碼。編輯之前復制的?main.c
?文件,把不需要的?lv_g2d_test
?的部分刪去。保留最基礎的部分。
#include "lvgl/lvgl.h"
#include "lv_drivers/display/sunxifb.h"
#include "lv_drivers/indev/evdev.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>static lv_style_t rect_style;
static lv_obj_t *rect_obj;
static lv_obj_t *canvas;int main(int argc, char *argv[]) {lv_disp_drv_t disp_drv;lv_disp_draw_buf_t disp_buf;lv_indev_drv_t indev_drv;uint32_t rotated = LV_DISP_ROT_NONE;lv_disp_drv_init(&disp_drv);/*LittlevGL init*/lv_init();/*Linux frame buffer device init*/sunxifb_init(rotated);/*A buffer for LittlevGL to draw the screen's content*/static uint32_t width, height;sunxifb_get_sizes(&width, &height);static lv_color_t *buf;buf = (lv_color_t*) sunxifb_alloc(width * height * sizeof(lv_color_t), "lv_2048");if (buf == NULL) {sunxifb_exit();printf("malloc draw buffer fail\n");return 0;}/*Initialize a descriptor for the buffer*/lv_disp_draw_buf_init(&disp_buf, buf, NULL, width * height);/*Initialize and register a display driver*/disp_drv.draw_buf = &disp_buf;disp_drv.flush_cb = sunxifb_flush;disp_drv.hor_res = width;disp_drv.ver_res = height;disp_drv.rotated = rotated;disp_drv.screen_transp = 0;lv_disp_drv_register(&disp_drv);evdev_init();lv_indev_drv_init(&indev_drv); /*Basic initialization*/indev_drv.type = LV_INDEV_TYPE_POINTER; /*See below.*/indev_drv.read_cb = evdev_read; /*See below.*//*Register the driver in LVGL and save the created input device object*/lv_indev_t *evdev_indev = lv_indev_drv_register(&indev_drv);/*Handle LitlevGL tasks (tickless mode)*/while (1) {lv_task_handler();usleep(1000);}return 0;
}/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
uint32_t custom_tick_get(void) {static uint64_t start_ms = 0;if (start_ms == 0) {struct timeval tv_start;gettimeofday(&tv_start, NULL);start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;}struct timeval tv_now;gettimeofday(&tv_now, NULL);uint64_t now_ms;now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;uint32_t time_ms = now_ms - start_ms;return time_ms;
}
接下來則是對接?lv_lib_100ask
?與?2048
?小游戲,我們先下載?lv_lib_100ask
?的源碼,放置到?platform/thirdparty/gui/lvgl-8/lv_2048
?的?src
?文件夾里。并按照?lv_lib_100ask
?的說明,復制一份?lv_lib_100ask_conf_template.h
?到?src
?目錄,并改名為?lv_lib_100ask_conf.h
編輯?lv_lib_100ask_conf.h
,開啟整個庫的引用,并配置啟用?LV_USE_100ASK_2048
?。為了簡潔,這里刪除了不需要的配置項。
/*** @file lv_lib_100ask_conf.h* Configuration file for v8.2.0**/
/** COPY THIS FILE AS lv_lib_100ask_conf.h*//* clang-format off */
#if 1 /*Set it to "1" to enable the content*/ #ifndef LV_LIB_100ASK_CONF_H
#define LV_LIB_100ASK_CONF_H#include "lv_conf.h"/******************** GENERAL SETTING*******************//********************** USAGE*********************/*2048 game*/
#define LV_USE_100ASK_2048 1
#if LV_USE_100ASK_2048/* Matrix size*//*Do not modify*/#define LV_100ASK_2048_MATRIX_SIZE 4/*test*/#define LV_100ASK_2048_SIMPLE_TEST 1
#endif #endif /*LV_LIB_100ASK_H*/#endif /*End of "Content enable"*/
再編輯?platform/thirdparty/gui/lvgl-8/lv_2048/src/lv_lib_100ask/lv_lib_100ask.h
?中的版本號,修改為?(8,1,0)
之后在?main.c
?里修改,對接?lv_100ask_2048_simple_test
,具體如下。
(1)頭文件加入?lv_lib_100ask/lv_lib_100ask.h
#include <lv_lib_100ask/lv_lib_100ask.h>
(2)在?main
?函數里添加接口調用
lv_100ask_2048_simple_test();
完整的?main.c
?如下
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>#include "lvgl/lvgl.h"
#include "lv_drivers/display/sunxifb.h"
#include "lv_drivers/indev/evdev.h"#include "lv_lib_100ask/lv_lib_100ask.h" // 引用頭文件static lv_style_t rect_style;
static lv_obj_t *rect_obj;
static lv_obj_t *canvas;int main(int argc, char *argv[]) {lv_disp_drv_t disp_drv;lv_disp_draw_buf_t disp_buf;lv_indev_drv_t indev_drv;uint32_t rotated = LV_DISP_ROT_NONE;lv_disp_drv_init(&disp_drv);/*LittlevGL init*/lv_init();/*Linux frame buffer device init*/sunxifb_init(rotated);/*A buffer for LittlevGL to draw the screen's content*/static uint32_t width, height;sunxifb_get_sizes(&width, &height);static lv_color_t *buf;buf = (lv_color_t*) sunxifb_alloc(width * height * sizeof(lv_color_t), "lv_nes");if (buf == NULL) {sunxifb_exit();printf("malloc draw buffer fail\n");return 0;}/*Initialize a descriptor for the buffer*/lv_disp_draw_buf_init(&disp_buf, buf, NULL, width * height);/*Initialize and register a display driver*/disp_drv.draw_buf = &disp_buf;disp_drv.flush_cb = sunxifb_flush;disp_drv.hor_res = width;disp_drv.ver_res = height;disp_drv.rotated = rotated;disp_drv.screen_transp = 0;lv_disp_drv_register(&disp_drv);evdev_init();lv_indev_drv_init(&indev_drv); /*Basic initialization*/indev_drv.type = LV_INDEV_TYPE_POINTER; /*See below.*/indev_drv.read_cb = evdev_read; /*See below.*//*Register the driver in LVGL and save the created input device object*/lv_indev_t *evdev_indev = lv_indev_drv_register(&indev_drv);lv_100ask_2048_simple_test(); // 調用 2048 小游戲/*Handle LitlevGL tasks (tickless mode)*/while (1) {lv_task_handler();usleep(1000);}return 0;
}/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
uint32_t custom_tick_get(void) {static uint64_t start_ms = 0;if (start_ms == 0) {struct timeval tv_start;gettimeofday(&tv_start, NULL);start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;}struct timeval tv_now;gettimeofday(&tv_now, NULL);uint64_t now_ms;now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;uint32_t time_ms = now_ms - start_ms;return time_ms;
}
然后就是?Makefile
?修改,增加一個?lv_lib_100ask
?的 SRC 引用。
include lv_lib_100ask/lv_lib_100ask.mk
順便也把?BIN
?改為?lv_2048
?,完整的?Makefile
?如下
#
# Makefile
#
CC ?= gcc
LVGL_DIR_NAME ?= lvgl
LVGL_DIR ?= ${shell pwd}
CFLAGS ?= -O3 -g0 -I$(LVGL_DIR)/ -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -Wall -Wextra -Wno-unused-function -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body -Wtype-limits -Wshift-negative-value -Wstack-usage=2048 -Wno-unused-value -Wno-unused-parameter -Wno-missing-field-initializers -Wuninitialized -Wmaybe-uninitialized -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wpointer-arith -Wno-cast-qual -Wmissing-prototypes -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wno-discarded-qualifiers -Wformat-security -Wno-ignored-qualifiers -Wno-sign-compare
LDFLAGS ?= -lm
BIN = lv_2048#Collect the files to compile
SRCDIRS = $(shell find . -maxdepth 1 -type d)
MAINSRC = $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c))include $(LVGL_DIR)/lvgl/lvgl.mk
include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
include lv_lib_100ask/lv_lib_100ask.mkOBJEXT ?= .oAOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))MAINOBJ = $(MAINSRC:.c=$(OBJEXT))SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS)## MAINOBJ -> OBJFILESall: default%.o: %.c@$(CC) $(CFLAGS) -c $< -o $@@echo "CC $<"default: $(AOBJS) $(COBJS) $(MAINOBJ)$(CC) -o $(BIN) $(MAINOBJ) $(AOBJS) $(COBJS) $(LDFLAGS)clean: rm -f $(BIN) $(AOBJS) $(COBJS) $(MAINOBJ)
對接觸摸
做了以上操作,可能會發現觸摸沒有反應,這是因為觸摸綁定的?event
?事件號不對,默認的綁定是?event3
?而查閱啟動?log
?可知,開發板的觸摸屏對接的是?event0
這時需要修改綁定的?event
?事件號,其配置文件在?lv_drv_conf.h
?內:
這里將?event3
?改為?event0
?即可
# define EVDEV_NAME "/dev/input/event0"
當然除了這樣的方法,另外也可以用命令生成軟連接?touchscreen
,就會直接以?touchscreen
?為觸摸節點,方便調試:
ln -s /dev/input/eventX /dev/input/touchscreen
測試編譯
修改好了,希望單獨編譯這個包測試下而不編譯完整的 SDK。可以這樣做:
(1)確保已經?source build/envsetup.sh
?并已經?lunch
(2)在任意文件夾下執行命令?mmo lv_2048 -B
其中?mmo
?的意思是 單獨編譯一個?openWrt
?軟件包,后面的?lv_2048
?是軟件包名。-B
?參數是先?clean
?再編譯,不加這個參數就是直接編譯了。
測試運行
編譯打包后,到開發板上使用?lv_2048
?即可運行