littlevgl(Lvgl)最新版V7.4移植

简介: littlevgl(Lvgl)最新版V7.4移植

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


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


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


关于lvgl的官网及介绍,在https://lvgl.io,Online demo:https://lvgl.io/demos,Docs:https://docs.lvgl.io



移植比较简单,主要区别是几个接口跟老版本的不一样了。不过最终都是实现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

。。。



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


/**
 * @file fbdev.c
 *
 */
/*********************
 *      INCLUDES
 *********************/
#include "fbdev.h"
#if USE_FBDEV
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
/*********************
 *      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 <unistd.h>
//#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
  @


#
# Makefile
#
CC = gcc
CFLAGS = -Wall -Wshadow -Wundef -Wmaybe-uninitialized
CFLAGS += -O3 -g3 -I./
#LDFLAGS += -lSDL2 -lm
BIN = demo
VPATH = 
MAINSRC = main.c
#LIBRARIES
include ./lvgl/lv_core/lv_core.mk
include ./lvgl/lv_hal/lv_hal.mk
include ./lvgl/lv_objx/lv_objx.mk
include ./lvgl/lv_misc/lv_fonts/lv_fonts.mk
include ./lvgl/lv_misc/lv_misc.mk
include ./lvgl/lv_themes/lv_themes.mk
include ./lvgl/lv_draw/lv_draw.mk
#DRIVERS
include ./lv_drivers/display/display.mk
include ./lv_drivers/indev/indev.mk
#EXAMPLE
include ./lv_examples/lv_apps/benchmark/benchmark.mk
OBJEXT ?= .o
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS)
## MAINOBJ -> OBJFILES
all: clean 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)


相关文章
|
Ubuntu 编译器 芯片
FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
|
1月前
【LVGL快速入门】SquareLine Studio安装教程(LVGL官方工具)
【LVGL快速入门】SquareLine Studio安装教程(LVGL官方工具)
311 0
|
Ubuntu NoSQL IDE
树莓派开发笔记(二):qt开发环境搭建:树莓派qt编译和宿主机qt交叉编译
树莓派开发笔记(二):qt开发环境搭建:树莓派qt编译和宿主机qt交叉编译
树莓派开发笔记(二):qt开发环境搭建:树莓派qt编译和宿主机qt交叉编译
|
5月前
|
存储 编解码 Ubuntu
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
|
Ubuntu Java 编译器
iMX6 yocto平台QT交叉编译环境搭建
iMX6 yocto平台QT交叉编译环境搭建
270 0
iMX6 yocto平台QT交叉编译环境搭建
|
存储 数据可视化 安全
ucgui在嵌入式linux下的移植
ucgui在嵌入式linux下的移植
|
Ubuntu Linux Shell
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(七)Ubuntu开发环境配置
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(七)Ubuntu开发环境配置
772 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(七)Ubuntu开发环境配置
|
JavaScript 开发工具 开发者
openHarmony开发环境搭建
从今天开始正式写openHarmony相关的文章,经过一段时间的沉淀,学习之路漫漫,不断地学习才是王道,熟话说万事开头难,安装软件应该是学习的第一道坎,废话不多说了,看内容了~~
322 0
openHarmony开发环境搭建
|
存储 Linux 开发工具
rockchip的yocto编译环境的搭建
rockchip的yocto编译环境的搭建
883 0
rockchip的yocto编译环境的搭建
|
Ubuntu 网络安全 数据安全/隐私保护
鸿蒙系统环境搭建、源码编译与烧写之经典
大家好,今天学习一下,如何部署鸿蒙环境,并在ubuntu系统下编译,以及烧写镜像的方法。 目录
412 0
鸿蒙系统环境搭建、源码编译与烧写之经典