glmark2移植到嵌入式Linux,littlevgl(Lvgl)最新版V7.4移植

LittleVGL最新已经更新到V7,网上大多数移植教程的版本比较老,很多特性没有,界面也不够酷炫。

原子最近更新的 LittleVGL 教程则是基于V6版本的,基本上搬过来全是报错,无法参考。新旧版本一致还是有很大区别的,这里介绍下最新版本的移植要点,针对嵌入式linux的framebuffer(dev/fb0)移植。

当然最最新的版本是V7.4.0,源码可以在github下载https://github.com/lvgl/lvgl。

glmark2移植到嵌入式Linux,littlevgl(Lvgl)最新版V7.4移植_第1张图片

移植比较简单,主要区别是几个接口跟老版本的不一样了。不过最终都是实现disp_flush显示驱动接口即可。

接口原型新版本的是这样的:

void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)

移植说明:

新建个工程文件夹,我这取名叫test,

然后在test文件夹下新建个lvgl文件夹,把下载到的源码中的src文件夹整个拷贝出来放进去。

把lv_conf_template.h拷贝出来,到工程的文件夹下,重命名为lv_conf.h.

编辑下,根据实际情况改下相关的配置:

#define LV_HOR_RES_MAX          (480)

#define LV_VER_RES_MAX          (272)

#define LV_COLOR_DEPTH     16

#define LV_USE_GPU              0

/* 1: Enable file system (might be required for images */

#define LV_USE_FILESYSTEM       1

。。。

glmark2移植到嵌入式Linux,littlevgl(Lvgl)最新版V7.4移植_第2张图片

在工程的文件夹下建个lv_drivers文件夹,用于实现的驱动文件。

/**

* @file fbdev.c

*

*/

/*********************

* INCLUDES

*********************/

#include "fbdev.h"

#if USE_FBDEV

#include

#include

#include

#include

#include

#include

#include

#include

/*********************

* DEFINES

*********************/

#ifndef FBDEV_PATH

#define FBDEV_PATH "/dev/fb0"

#endif

/**********************

* TYPEDEFS

**********************/

/**********************

* STATIC PROTOTYPES

**********************/

/**********************

* STATIC VARIABLES

**********************/

static struct fb_var_screeninfo vinfo;

static struct fb_fix_screeninfo finfo;

static char *fbp = 0;

static long int screensize = 0;

static int fbfd = 0;

/**********************

* MACROS

**********************/

/**********************

* GLOBAL FUNCTIONS

**********************/

void fbdev_init(void)

{

// Open the file for reading and writing

fbfd = open(FBDEV_PATH, O_RDWR);

if (fbfd == -1) {

perror("Error: cannot open framebuffer device");

return;

}

printf("The framebuffer device was opened successfully.\n");

// Get fixed screen information

if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {

perror("Error reading fixed information");

return;

}

// Get variable screen information

if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {

perror("Error reading variable information");

return;

}

printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

// Figure out the size of the screen in bytes

screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

// Map the device to memory

fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);

if ((int)fbp == -1) {

perror("Error: failed to map framebuffer device to memory");

return;

}

printf("The framebuffer device was mapped to memory successfully.\n");

}

/**

* Flush a buffer to the marked area

* @param x1 left coordinate

* @param y1 top coordinate

* @param x2 right coordinate

* @param y2 bottom coordinate

* @param color_p an array of colors

*/

void fbdev_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)

{

if(fbp == NULL) return;

/*Return if the area is out the screen*/

if(x2 < 0) return;

if(y2 < 0) return;

if(x1 > vinfo.xres - 1) return;

if(y1 > vinfo.yres - 1) return;

/*Truncate the area to the screen*/

int32_t act_x1 = x1 < 0 ? 0 : x1;

int32_t act_y1 = y1 < 0 ? 0 : y1;

int32_t act_x2 = x2 > vinfo.xres - 1 ? vinfo.xres - 1 : x2;

int32_t act_y2 = y2 > vinfo.yres - 1 ? vinfo.yres - 1 : y2;

long int location = 0;

/*32 or 24 bit per pixel*/

if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {

uint32_t *fbp32 = (uint32_t*)fbp;

uint32_t x;

uint32_t y;

for(y = act_y1; y <= act_y2; y++) {

for(x = act_x1; x <= act_x2; x++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp32[location] = color_p->full;

color_p++;

}

color_p += x2 - act_x2;

}

}

/*16 bit per pixel*/

else if(vinfo.bits_per_pixel == 16) {

uint16_t *fbp16 = (uint16_t*)fbp;

uint32_t x;

uint32_t y;

for(y = act_y1; y <= act_y2; y++) {

for(x = act_x1; x <= act_x2; x++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp16[location] = color_p->full;

color_p++;

}

color_p += x2 - act_x2;

}

}

/*8 bit per pixel*/

else if(vinfo.bits_per_pixel == 8) {

uint8_t *fbp8 = (uint8_t*)fbp;

uint32_t x;

uint32_t y;

for(y = act_y1; y <= act_y2; y++) {

for(x = act_x1; x <= act_x2; x++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp8[location] = color_p->full;

color_p++;

}

color_p += x2 - act_x2;

}

} else {

/*Not supported bit per pixel*/

}

//May be some direct update command is required

//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));

//lv_flush_ready();

/* IMPORTANT!!!

* Inform the graphics library that you are ready with the flushing*/

}

/* Flush the content of the internal buffer the specific area on the display

* You can use DMA or any hardware acceleration to do this operation in the background but

* 'lv_disp_flush_ready()' has to be called when finished. */

void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)

{

/* IMPORTANT!!!

* Inform the graphics library that you are ready with the flushing*/

fbdev_flush(area->x1,area->y1,area->x2,area->y2,color_p);

lv_disp_flush_ready(disp_drv);

}

/**

* Fill out the marked area with a color

* @param x1 left coordinate

* @param y1 top coordinate

* @param x2 right coordinate

* @param y2 bottom coordinate

* @param color fill color

*/

void fbdev_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)

{

if(fbp == NULL) return;

/*Return if the area is out the screen*/

if(x2 < 0) return;

if(y2 < 0) return;

if(x1 > vinfo.xres - 1) return;

if(y1 > vinfo.yres - 1) return;

/*Truncate the area to the screen*/

int32_t act_x1 = x1 < 0 ? 0 : x1;

int32_t act_y1 = y1 < 0 ? 0 : y1;

int32_t act_x2 = x2 > vinfo.xres - 1 ? vinfo.xres - 1 : x2;

int32_t act_y2 = y2 > vinfo.yres - 1 ? vinfo.yres - 1 : y2;

uint32_t x;

uint32_t y;

long int location = 0;

/*32 or 24 bit per pixel*/

if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {

uint32_t *fbp32 = (uint32_t*)fbp;

for(x = act_x1; x <= act_x2; x++) {

for(y = act_y1; y <= act_y2; y++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp32[location] = color.full;

}

}

}

else if(vinfo.bits_per_pixel == 16) {

uint16_t *fbp16 = (uint16_t*)fbp;

for(x = act_x1; x <= act_x2; x++) {

for(y = act_y1; y <= act_y2; y++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp16[location] = color.full;

}

}

}

else if(vinfo.bits_per_pixel == 8) {

uint8_t *fbp8 = (uint8_t*)fbp;

for(x = act_x1; x <= act_x2; x++) {

for(y = act_y1; y <= act_y2; y++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp8[location] = color.full;

}

}

} else {

/*Not supported bit per pixel*/

}

//May be some direct update command is required

//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));

}

/**

* Put a color map to the marked area

* @param x1 left coordinate

* @param y1 top coordinate

* @param x2 right coordinate

* @param y2 bottom coordinate

* @param color_p an array of colors

*/

void fbdev_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)

{

if(fbp == NULL) return;

/*Return if the area is out the screen*/

if(x2 < 0) return;

if(y2 < 0) return;

if(x1 > vinfo.xres - 1) return;

if(y1 > vinfo.yres - 1) return;

/*Truncate the area to the screen*/

int32_t act_x1 = x1 < 0 ? 0 : x1;

int32_t act_y1 = y1 < 0 ? 0 : y1;

int32_t act_x2 = x2 > vinfo.xres - 1 ? vinfo.xres - 1 : x2;

int32_t act_y2 = y2 > vinfo.yres - 1 ? vinfo.yres - 1 : y2;

long int location = 0;

/*32 or 24 bit per pixel*/

if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {

uint32_t *fbp32 = (uint32_t*)fbp;

uint32_t x;

uint32_t y;

for(y = act_y1; y <= act_y2; y++) {

for(x = act_x1; x <= act_x2; x++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp32[location] = color_p->full;

color_p++;

}

color_p += x2 - act_x2;

}

}

/*16 bit per pixel*/

else if(vinfo.bits_per_pixel == 16) {

uint16_t *fbp16 = (uint16_t*)fbp;

uint32_t x;

uint32_t y;

for(y = act_y1; y <= act_y2; y++) {

for(x = act_x1; x <= act_x2; x++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp16[location] = color_p->full;

color_p++;

}

color_p += x2 - act_x2;

}

}

/*8 bit per pixel*/

else if(vinfo.bits_per_pixel == 8) {

uint8_t *fbp8 = (uint8_t*)fbp;

uint32_t x;

uint32_t y;

for(y = act_y1; y <= act_y2; y++) {

for(x = act_x1; x <= act_x2; x++) {

location = (x+vinfo.xoffset) + (y+vinfo.yoffset) * vinfo.xres;

fbp8[location] = color_p->full;

color_p++;

}

color_p += x2 - act_x2;

}

} else {

/*Not supported bit per pixel*/

}

//May be some direct update command is required

//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));

}

/**********************

* STATIC FUNCTIONS

**********************/

#endif

附上一个小测试demo:

#include "lvgl.h"

#include "lv_drivers/display/fbdev.h"

#include

//#include "lv_examples/lv_apps/demo/demo.h"

static lv_disp_buf_t disp_buf_2;

static lv_color_t buf2_1[LV_HOR_RES_MAX * 10]; /*A buffer for 10 rows*/

static lv_color_t buf2_2[LV_HOR_RES_MAX * 10]; /*An other buffer for 10 rows*/

//extern void demo_create(void);

int main(void)

{

/*LittlevGL init*/

lv_init();

/*Linux frame buffer device init*/

fbdev_init();

/*Add a display the LittlevGL sing the frame buffer driver*/

lv_disp_drv_t disp_drv;

lv_disp_drv_init(&disp_drv);

disp_drv.flush_cb = disp_flush;

/*Set a display buffer*/

lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/

disp_drv.buffer = &disp_buf_2;

//disp_drv.disp_flush = fbdev_flush; /*It flushes the internal graphical buffer to the frame buffer*/

lv_disp_drv_register(&disp_drv);

/*Create a "Hello world!" label*/

lv_obj_t * label = lv_label_create(lv_scr_act(), NULL);

lv_label_set_text(label, "hello worldaaa!v7.4");

lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);

/*Handle LitlevGL tasks (tickless mode)*/

//demo_create();

while(1) {

lv_tick_inc(5);

lv_task_handler();

usleep(5000);

}

return 0;

}

如何运行?直接make即可生成可执行文件。

附makefile文件:

########################################

#makefile

########################################

#****************************************************************************

# Cross complie path

#****************************************************************************

CHAIN_ROOT= /home/yang/crosstool/ctools/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin

CROSS_COMPILE=$(CHAIN_ROOT)/arm-linux-gnueabihf-

#CROSS_COMPILE =

CC := $(CROSS_COMPILE)gcc

CXX := $(CROSS_COMPILE)g++

AS := $(CROSS_COMPILE)as

AR := $(CROSS_COMPILE)ar

LD := $(CROSS_COMPILE)ld

RANLIB := $(CROSS_COMPILE)ranlib

OBJDUMP:= $(CROSS_COMPILE)objdump

OBJCOPY:= $(CROSS_COMPILE)objcopy

STRIP := $(CROSS_COMPILE)strip

#编译主程序

BINARY := littlevgl

OBJ_DIR := ./

INCS := -I ./ -I./lvgl/src/

CFLAGS= -Wall -g -std=c99 -fno-common -fsanitize=address -fno-stack-protector -fno-omit-frame-pointer -fno-var-tracking

#****************************************************************************

# Source files

#****************************************************************************

SRC_C=$(shell find . -name "*.c")

OBJ_C=$(patsubst %.c, %.o, $(SRC_C))

SRCS := $(SRC_C) $(SRC_C)

OBJS := $(OBJ_C)

LDSCRIPT= -lasan

LDFLAGS= -Llibs

#LDSCRIPT= -lNC_FileSys

#LDFLAGS= -Llib

#SRC = $(wildcard *.c)

#DIR = $(notdir $(SRC))

#OBJS = $(patsubst %.c,$(OBJ_DIR)%.o,$(DIR))

#OBJS= main.o myutils.o inirw.o cmdpboc.o cputest.o bustcp.o ansrec.o m1cmd.o m1api.o m1test.o upcash.o myother.o getsys.o

#CFLAGS=-std=c99

#@echo Building lib...

#$(call make_subdir)

.PHONY: clean

all: prebuild $(BINARY)

prebuild:

@echo Building app...

$(BINARY) : $(OBJS)

@echo Generating ...

$(CC) -o $(BINARY) $(OBJS) $(LDFLAGS) $(LDSCRIPT)

@echo OK!

$(OBJ_DIR)%.o : %.c

$(CC) -c $(CFLAGS) $(INCS) $< -o $@

clean:

rm -f $(OBJ_DIR)*.o

find . -name "*.[od]" |xargs rm

@

你可能感兴趣的:(glmark2移植到嵌入式Linux,littlevgl(Lvgl)最新版V7.4移植)