From 80686e6bc4cb17e9d856647084725203fa63ebe6 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Mon, 19 Aug 2024 16:47:42 +0800
Subject: [PATCH] Add LCD API examples

---
 hal/lcd/lvgl/lvgl_demo.c                                      |   91 ++++
 hal/lcd/lvgl/libs_lvgl/patches/lv_drivers-8.0.1-imx6ull.patch |  103 ++++
 hal/lcd/drm/libs/build.sh                                     |   44 ++
 hal/lcd/lvgl/libs_lvgl/build.sh                               |   72 +++
 hal/lcd/lvgl/makefile                                         |   46 ++
 hal/lcd/fb/fbtest.c                                           |  396 ++++++++++++++++++
 hal/lcd/fb/makefile                                           |   43 +
 hal/lcd/drm/libs/libdrm/build.sh                              |   98 ++++
 hal/lcd/lvgl/libs_lvgl/patches/gen_patch.sh                   |   55 ++
 hal/lcd/lvgl/libs_lvgl/patches/lvgl-8.0.2-imx6ull.patch       |   92 ++++
 hal/lcd/lvgl/libs_lvgl/patches/lv_demos-8.0.1-imx6ull.patch   |   49 ++
 hal/lcd/drm/drm_test.c                                        |  154 +++++++
 hal/lcd/drm/makefile                                          |   50 ++
 13 files changed, 1,293 insertions(+), 0 deletions(-)

diff --git a/hal/lcd/drm/drm_test.c b/hal/lcd/drm/drm_test.c
new file mode 100644
index 0000000..e3cf6ca
--- /dev/null
+++ b/hal/lcd/drm/drm_test.c
@@ -0,0 +1,154 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+struct buffer_object {
+    
+	uint32_t width;
+	uint32_t height;
+	uint32_t pitch;
+	uint32_t handle;
+	uint32_t size;
+	uint32_t *vaddr;
+	uint32_t fb_id;
+};
+
+struct buffer_object buf[3];
+
+static int modeset_create_fb(int fd, struct buffer_object *bo, uint32_t color)
+{
+    
+	struct drm_mode_create_dumb create = {
+    };
+ 	struct drm_mode_map_dumb map = {
+    };
+	uint32_t i;
+
+	create.width = bo->width;
+	create.height = bo->height;
+	create.bpp = 32;
+	drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
+
+	bo->pitch = create.pitch;
+	bo->size = create.size;
+	bo->handle = create.handle;
+	drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch,
+			   bo->handle, &bo->fb_id);
+
+	map.handle = create.handle;
+	drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
+
+	bo->vaddr = mmap(0, create.size, PROT_READ | PROT_WRITE,
+			MAP_SHARED, fd, map.offset);
+
+	for (i = 0; i < (bo->size / 4); i++)
+		bo->vaddr[i] = color;
+
+	return 0;
+}
+
+static void modeset_destroy_fb(int fd, struct buffer_object *bo)
+{
+    
+	struct drm_mode_destroy_dumb destroy = {
+    };
+
+	drmModeRmFB(fd, bo->fb_id);
+
+	munmap(bo->vaddr, bo->size);
+
+	destroy.handle = bo->handle;
+	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
+}
+
+int main(int argc, char **argv)
+{
+	char             *dri_card="/dev/dri/card0";
+	int               fd;
+	uint32_t          conn_id;
+	uint32_t          crtc_id;
+	drmModeConnector *conn;
+	drmModeRes       *res;
+
+	if( argc != 2 )
+	{
+		printf("Usage: %s /dev/dri/card0\n", argv[0]);
+		return 1;
+	}
+	else
+	{
+		dri_card = argv[1];
+	}
+
+	fd = open(dri_card, O_RDWR | O_CLOEXEC);
+	if( fd < 0)
+	{
+		printf("Open '%s' failure: %s\n", dri_card, strerror(errno));
+		return 0;
+	}
+
+	res = drmModeGetResources(fd);
+	if( !res )
+	{
+		printf("drmModeGetResources() failure\n");
+		return 0;
+	}
+
+	crtc_id = res->crtcs[0];
+	conn_id = res->connectors[0];
+
+	conn = drmModeGetConnector(fd, conn_id);
+	if( !conn )
+	{
+		printf("drmModeGetConnector() failure\n");
+		return 0;
+	}
+
+	buf[0].width = conn->modes[0].hdisplay;
+	buf[0].height = conn->modes[0].vdisplay;
+	buf[1].width = conn->modes[0].hdisplay;
+	buf[1].height = conn->modes[0].vdisplay;
+	buf[2].width = conn->modes[0].hdisplay;
+	buf[2].height = conn->modes[0].vdisplay;
+
+	printf("DRM create framebuffer now.\n");
+	modeset_create_fb(fd, &buf[0], 0xff0000);
+	modeset_create_fb(fd, &buf[1], 0x00ff00);
+	modeset_create_fb(fd, &buf[2], 0x0000ff);
+
+	printf("Show red screen on LCD.\n");
+	drmModeSetCrtc(fd, crtc_id, buf[0].fb_id, 0, 0, &conn_id, 1, &conn->modes[0]);
+	getchar();
+
+	printf("Show green screen on LCD.\n");
+	drmModeSetCrtc(fd, crtc_id, buf[1].fb_id, 0, 0, &conn_id, 1, &conn->modes[0]);
+	getchar();
+
+	printf("Show blue screen on LCD.\n");
+	drmModeSetCrtc(fd, crtc_id, buf[2].fb_id, 0, 0, &conn_id, 1, &conn->modes[0]);
+	getchar();
+
+	printf("DRM destroy framebuffer now.\n");
+	modeset_destroy_fb(fd, &buf[0]);
+	modeset_destroy_fb(fd, &buf[1]);
+	modeset_destroy_fb(fd, &buf[2]);
+
+	drmModeFreeConnector(conn);
+	return 0;
+	drmModeFreeResources(res);
+
+	close(fd);
+
+	return 0;
+}
+
diff --git a/hal/lcd/drm/libs/build.sh b/hal/lcd/drm/libs/build.sh
new file mode 100755
index 0000000..bdc2729
--- /dev/null
+++ b/hal/lcd/drm/libs/build.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+function do_compile
+{
+    for dir in `ls`
+    do  
+        if [ -f $dir/build*.sh ] ; then
+            cd $dir
+               ./build*.sh
+            cd -
+        fi  
+    done
+}
+
+function do_distclean
+{
+    for dir in `ls`
+    do  
+        if [ -f $dir/build*.sh ] ; then
+            rm -rf ${dir}/${dir}*
+        fi  
+    done
+}
+
+if [ $# == 1 ] ; then 
+    if [ $1 == "clean" ] ; then 
+        rm -rf install
+        exit;
+    elif [ $1 == "distclean" ] ; then
+        rm -rf install
+        do_distclean
+        exit;
+    fi  
+
+	# export cross compiler
+	if echo $1 | grep "\-linux\-" > /dev/null 2>&1 ; then
+		export CROSS_COMPILE=$1
+		echo -e "\033[40;33m --W-- export cross compiler $CROSS_COMPILE \033[0m\n"
+	fi
+fi
+
+
+do_compile
+
diff --git a/hal/lcd/drm/libs/libdrm/build.sh b/hal/lcd/drm/libs/libdrm/build.sh
new file mode 100755
index 0000000..2574193
--- /dev/null
+++ b/hal/lcd/drm/libs/libdrm/build.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+#+--------------------------------------------------------------------------------------------
+#|Description:  This shell script used download and cross compile open source libs
+#|     Author:  GuoWenxue <guowenxue@gmail.com>
+#|  ChangeLog:
+#|           1, Initialize 1.0.0 on 2011.04.12
+#+--------------------------------------------------------------------------------------------
+
+SCRIPT_PATH=`dirname ${BASH_SOURCE[0]}`
+PREFIX_PATH=`realpath ${SCRIPT_PATH}/`/../install
+
+CONF_FILE=cross_file.txt
+
+# display in yellow
+function pr_warn() {
+    echo -e "\033[40;33m --W-- $1 \033[0m\n"
+}
+
+function generate_config()
+{
+cat > $CONF_FILE <<EOF
+
+[binaries]
+c = '${CROSS_COMPILE}gcc'
+cpp = '${CROSS_COMPILE}g++'
+ar = '${CROSS_COMPILE}ar'
+strip = '${CROSS_COMPILE}strip'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'arm'
+cpu = 'armv7'
+endian = 'little'
+
+[build_machine]
+system = 'linux'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+EOF
+}
+
+function compile_libdrm()
+{
+    SRC_NAME=libdrm-2.4.110
+
+	echo $PREFIX_PATH
+
+    if [ -f ${PREFIX_PATH}/bin/modetest ] ; then
+        pr_warn "$SRC_NAME already compile and installed"
+        return 0;
+    fi
+
+    pr_warn "Start compile $SRC_NAME "
+
+    if [ ! -d $SRC_NAME ] ; then
+	   if [ ! -f ${SRC_NAME}.tar.xz ] ; then
+		   wget https://dri.freedesktop.org/libdrm/${SRC_NAME}.tar.xz
+	   fi
+
+	   tar -xJf ${SRC_NAME}.tar.xz
+    fi
+
+    cd ${SRC_NAME}
+
+	generate_config
+
+	BUILD_PATH=tmp_build
+	rm -rf $BUILD_PATH && mkdir -p $BUILD_PATH && cd $BUILD_PATH
+
+	meson --prefix=$PREFIX_PATH \
+          --cross-file=../$CONF_FILE \
+          -D amdgpu=false \
+          -D cairo-tests=false \
+          -D etnaviv=false \
+          -D exynos=false \
+          -D freedreno=false \
+          -D freedreno-kgsl=false \
+          -D install-test-programs=true \
+          -D intel=false \
+          -D libkms=false \
+          -D man-pages=false \
+          -D nouveau=false \
+          -D omap=false \
+          -D radeon=false \
+          -D tegra=false \
+          -D udev=false \
+          -D valgrind=false \
+          -D vc4=false \
+          -D vmwgfx=false
+
+	ninja && ninja install
+}
+
+compile_libdrm
+
diff --git a/hal/lcd/drm/makefile b/hal/lcd/drm/makefile
new file mode 100644
index 0000000..76f206c
--- /dev/null
+++ b/hal/lcd/drm/makefile
@@ -0,0 +1,50 @@
+#*********************************************************************************
+#      Copyright:  (C) 2022 Avnet. All rights reserved.
+#         Author:  Guo Wenxue<wenxue.guo@avnet.com>
+#
+#       Filename:  Makefile
+#    Description:  This Makefile used to compile all the C source code file in
+#                  current folder to a excutable binary file.
+#
+#********************************************************************************/
+
+PRJ_PATH=$(shell pwd)
+APP_NAME = drm_test
+
+CROSS_COMPILE=arm-linux-gnueabihf-
+
+# C source files in top-level directory
+SRCFILES = $(wildcard *.c)
+
+# common CFLAGS for our source code
+CFLAGS = -Wall -Wshadow -Wundef -Wmaybe-uninitialized
+
+# CFLAGS and LDFLAGS for opensource library in libs
+CFLAGS+=-I ${PRJ_PATH}
+CFLAGS+=-I ${PRJ_PATH}/libs/install/include/
+CFLAGS+=-I ${PRJ_PATH}/libs/install/include/libdrm
+LDFLAGS+=-L ${PRJ_PATH}/libs/install/lib
+LDFLAGS+=-L ${PRJ_PATH}/libs/install/lib
+
+LIBS+=-ldrm
+
+.PHONY:libs
+all: libs binary
+
+libs:
+	cd libs && ./build.sh ${CROSS_COMPILE}
+
+modules:
+	@set -e; for d in ${DIRS}; do $(MAKE) CROSS_COMPILE=${CROSS_COMPILE} CFLAGS="${CFLAGS}" -C $${d}; done
+
+binary:  ${SRCFILES}
+	$(CROSS_COMPILE)gcc $(CFLAGS) -o ${APP_NAME} $^ ${LDFLAGS} ${LIBS}
+	@echo " Compile over"
+
+#set -e; for d in ${DIRS}; do $(MAKE) clean -C $${d}; done
+clean:
+	@rm -f *.o $(APP_NAME)
+
+distclean: clean
+	@rm -rf cscope* tags
+	@cd libs && ./build.sh distclean
diff --git a/hal/lcd/fb/fbtest.c b/hal/lcd/fb/fbtest.c
new file mode 100644
index 0000000..43f8693
--- /dev/null
+++ b/hal/lcd/fb/fbtest.c
@@ -0,0 +1,396 @@
+/********************************************************************************
+ *      Copyright:  (C) 2023 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  fbtest.c
+ *    Description:  This program used to:
+ *                  1, Show framebuffer device information
+ *                  2, Show RGB color on LCD full screen
+ *                  3, Show BMP file on LCD;
+ *
+ *        Version:  1.0.0(08/19/23)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "08/19/23 12:56:31"
+ *                 
+ ********************************************************************************/
+
+#include <stdio.h>  
+#include <stdlib.h>  
+#include <stdint.h>  
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>  
+#include <fcntl.h>  
+#include <getopt.h>
+#include <libgen.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/fb.h>  
+#include <sys/mman.h>  
+
+#define PROG_VERSION      "1.0.0"
+
+enum
+{
+    CMD_SHOW_INFO, /* show LCD info  */
+    CMD_SHOW_RGB,  /* show RGB color */
+    CMD_SHOW_BMP,  /* show BMP file  */
+};
+
+typedef struct fb_ctx_s 
+{
+    int                       fd;       /* framebuffer file descriptor */
+    char                      dev[64];  /* framebuffer device name */
+    long                      fb_size;  /* framebuffer size */
+    int                       pix_size; /* lcd screen pix size  */
+    struct fb_var_screeninfo  vinfo;    /* framebuffer var information */
+    char                     *fbp;      /* framebuffer mmap() address */
+} fb_ctx_t; 
+
+
+int fb_init(fb_ctx_t *fb_ctx);
+int fb_term(fb_ctx_t *fb_ctx);
+int show_rgb(fb_ctx_t *fb_ctx, int times);
+int show_bmp(fb_ctx_t *fb_ctx, char *bmp_file);
+
+static void program_usage(char *progname)
+{
+    printf("Usage: %s [OPTION]...\n", progname);
+    printf(" %s is a program to show RGB color or BMP file on LCD screen\n", progname);
+
+    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
+    printf(" -d[device  ]  Specify framebuffer device, such as: /dev/fb0\n");
+    printf(" -c[color   ]  Display RGB corlor on LCD screen for some times, such as: -c 3\n");
+    printf(" -b[bmp     ]  Display BMP file, such as: -b bg.bmp\n");
+    printf(" -h[help    ]  Display this help information\n");
+    printf(" -v[version ]  Display the program version\n");
+
+    printf("\n%s version %s\n", progname, PROG_VERSION);
+    return;
+}
+
+int main (int argc, char **argv)
+{  
+    fb_ctx_t                  fb_ctx;
+    char                     *progname=NULL;
+    char                     *bmp_file=NULL;
+    char                     *fb_dev="/dev/fb0";
+    int                       cmd = CMD_SHOW_INFO;
+    int                       opt, times;
+
+    struct option long_options[] = { 
+        {"device", required_argument, NULL, 'd'},
+        {"color", required_argument, NULL, 'c'},
+        {"bmp", required_argument, NULL, 'b'},
+        {"version", no_argument, NULL, 'v'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0}
+    };
+
+    progname = (char *)basename(argv[0]);
+
+    /* Parser the command line parameters */
+    while ((opt = getopt_long(argc, argv, "d:c:b:vh", long_options, NULL)) != -1)
+    {
+        switch (opt)
+        {
+            case 'd': /* Set framebuffer device */
+                 fb_dev = optarg;
+                break;
+
+            case 'b': /* Set BMP file */
+                bmp_file = optarg;
+                cmd = CMD_SHOW_BMP;
+                break;
+
+            case 'c': /* Show RGB color */
+                times = atoi(optarg);
+                cmd = CMD_SHOW_RGB;
+                break;
+
+            case 'v':  /* Get software version */
+                printf("%s version %s\n", progname, PROG_VERSION);
+                return 0;
+
+            case 'h':  /* Get help information */
+                program_usage(progname);
+                return 0;
+
+            default:
+                break;
+        }
+
+    }
+
+    memset(&fb_ctx, 0, sizeof(fb_ctx));
+    strncpy(fb_ctx.dev, fb_dev, sizeof(fb_ctx.dev));
+
+    if( fb_init(&fb_ctx) < 0 )
+    {
+        printf("ERROR: Initial framebuffer device '%s' failure.\n", fb_ctx.dev);
+        return 1;
+    }
+
+    switch( cmd )
+    {
+        case CMD_SHOW_RGB:
+            show_rgb(&fb_ctx, times);
+            break;
+
+        case CMD_SHOW_BMP:
+            show_bmp(&fb_ctx, bmp_file);
+            break;
+
+        default:
+            break;
+    }
+
+    fb_term(&fb_ctx);
+
+    return 0;
+}
+
+
+int fb_get_var_screeninfo(int fd, struct fb_var_screeninfo *vinfo)
+{
+    if( fd<0 || !vinfo )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+ 
+    if(ioctl(fd, FBIOGET_VSCREENINFO, vinfo))
+    {
+        printf("ERROR: ioctl() get variable info failure: %s\n", strerror(errno));  
+        return -2;
+    }  
+
+    printf("LCD information : %dx%d, bpp:%d rgba:%d/%d,%d/%d,%d/%d,%d/%d\n", vinfo->xres, vinfo->yres, vinfo->bits_per_pixel,
+            vinfo->red.length, vinfo->red.offset, vinfo->green.length, vinfo->green.offset, 
+			vinfo->blue.length,vinfo->blue.offset, vinfo->transp.length, vinfo->transp.offset);
+
+    return 0;
+}
+
+int fb_init(fb_ctx_t *fb_ctx)
+{
+    struct fb_var_screeninfo    *vinfo;
+
+    if( !fb_ctx || !strlen(fb_ctx->dev) )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    if( (fb_ctx->fd=open(fb_ctx->dev, O_RDWR)) < 0 )
+    {
+        printf("ERROR: Open framebuffer device '%s' failure: %s\n", fb_ctx->dev, strerror(errno));  
+        return -2;
+    } 
+
+    fb_get_var_screeninfo(fb_ctx->fd, &fb_ctx->vinfo);
+
+    vinfo = &fb_ctx->vinfo;
+    fb_ctx->fb_size = vinfo->xres * vinfo->yres * vinfo->bits_per_pixel / 8;  
+    fb_ctx->pix_size = vinfo->xres * vinfo->yres;
+
+    fb_ctx->fbp =(char *)mmap(0, fb_ctx->fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_ctx->fd ,0);  
+    if ( !fb_ctx->fbp )  
+    {    
+        printf ("ERROR: Framebuffer mmap() failure: %s\n", strerror(errno));  
+        return -2;
+    }
+
+    vinfo->xoffset = 0;
+    vinfo->yoffset = 0;
+
+    return 0;
+}
+
+int fb_term(fb_ctx_t *fb_ctx)
+{
+    if( !fb_ctx )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    munmap(fb_ctx->fbp, fb_ctx->fb_size);
+    close (fb_ctx->fd);
+ 
+    return 0;
+}
+
+int show_rgb_screen(fb_ctx_t *fb_ctx)
+{
+    struct fb_var_screeninfo    *vinfo;
+    char                        *fb_addr;
+    int                          interval = 1;
+    int                          i, color;
+    int                          bpp_bytes;
+
+    if( !fb_ctx )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    vinfo = &fb_ctx->vinfo;
+    bpp_bytes = vinfo->bits_per_pixel / 8;
+
+    printf("show full screen on red\n");
+    color = (1<<vinfo->red.length-1) << vinfo->red.offset;
+    fb_addr = fb_ctx->fbp;
+    for(i=0; i<fb_ctx->pix_size; i++)
+    {
+        memcpy(fb_addr, &color, bpp_bytes);
+        fb_addr += bpp_bytes;
+    }
+    sleep(interval);
+
+    printf("show full screen on green\n");
+    color = (1<<vinfo->green.length-1) << vinfo->green.offset;
+    fb_addr = fb_ctx->fbp;
+    for(i=0; i<fb_ctx->pix_size; i++)
+    {
+        memcpy(fb_addr, &color, bpp_bytes);
+        fb_addr += bpp_bytes;
+    }
+    sleep(interval);
+
+    printf("show full screen on blue\n");
+    color = (1<<vinfo->blue.length-1) << vinfo->blue.offset;
+    fb_addr = fb_ctx->fbp;
+    for(i=0; i<fb_ctx->pix_size; i++)
+    {
+        memcpy(fb_addr, &color, bpp_bytes);
+        fb_addr += bpp_bytes;
+    }
+    sleep(interval);
+
+    return 0;
+}
+
+int show_rgb(fb_ctx_t *fb_ctx, int times)
+{
+    int       i;
+
+    if( !fb_ctx )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    for(i=0; i<times; i++)
+    {
+        show_rgb_screen(fb_ctx);
+    }
+
+    return 0;
+}
+
+
+/* BMP format: https://blog.csdn.net/weixin_39756273/article/details/110585675  */
+typedef struct bmp_file_head_s 
+{
+    uint8_t  bfType[2];        /* BMP file type: "BM" */
+    int32_t bfSize;           /* BMP file size */
+    int32_t bfReserved;       /* reserved */
+    int32_t bfoffBits;        /* image data offset */
+}__attribute__((packed)) bmp_file_head_t; 
+
+
+typedef struct bmp_bitmap_info_s 
+{
+    int32_t biSize;           /* this struture size */
+    int32_t biWidth;          /* image width in pix */
+    int32_t biHeight;         /* image height in pix */
+    uint16_t biPlanes;         /* display planes, always be 1 */
+    uint16_t biBitCount;       /* bpp: 1,4,8,16,24,32 */
+    int32_t biCompress;       /* compress type */
+    int32_t biSizeImage;      /* image size in byte */
+    int32_t biXPelsPerMeter;  /* x-res in pix/m */
+    int32_t biYPelsPerMeter;  /* y-res in pix/m */
+    int32_t biClrUsed;
+    int32_t biClrImportant;
+}__attribute__((packed)) bmp_bitmap_info_t; 
+
+/*
+ * BMP image file format:
+ * +----------------+------------------+--------------------+---------------+
+ * | File Head(14B) | Bitmap Info(40B) | color palette(OPT) |  bitmap data  |
+ * +----------------+------------------+--------------------+---------------+
+ */
+int show_bmp(fb_ctx_t *fb_ctx, char *bmp_file)
+{
+    struct fb_var_screeninfo    *vinfo;
+    char                        *fb_addr;
+    bmp_file_head_t            *file_head;
+    bmp_bitmap_info_t          *bitmap_info;
+    struct stat                 statbuf;
+    char                       *f_addr;
+    char                       *d_addr;
+    char                       *p_addr;
+    int                         fd;
+    int                         bpp_bytes;
+    int                         i, j;
+	int                         width, height;
+
+    if( !fb_ctx || !bmp_file )
+    {
+        printf("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    if( (fd=open(bmp_file, O_RDONLY)) < 0 )
+    {
+        printf("ERROR: Open file '%s' failure: %s\n", bmp_file, strerror(errno));
+        return -2;
+    }
+
+    fstat(fd, &statbuf);
+    f_addr =(char *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd ,0);  
+    if ( !f_addr )   
+    {    
+        printf ("ERROR: BMP file mmap() failure: %s\n", strerror(errno));  
+        return -2; 
+    }   
+
+    /* BMP file header */
+    file_head = (bmp_file_head_t *)f_addr;
+    if( memcmp(file_head->bfType, "BM", 2) != 0)  
+    {
+        printf("ERROR: It's not a BMP file\n");
+        return -3;
+    }
+
+    /* BMP bitmap information header */
+    bitmap_info = (bmp_bitmap_info_t *)(f_addr+sizeof(bmp_file_head_t));
+
+    /* BMP bitmap data */
+    d_addr = f_addr + file_head->bfoffBits;
+
+    vinfo = &fb_ctx->vinfo;
+    fb_addr = fb_ctx->fbp;
+    bpp_bytes = vinfo->bits_per_pixel / 8;
+
+    width = bitmap_info->biWidth>vinfo->xres ? vinfo->xres : bitmap_info->biWidth;
+    height = bitmap_info->biHeight>vinfo->yres ? vinfo->yres : bitmap_info->biHeight;
+
+    printf("BMP file '%s': %dx%d and display %dx%d\n", bmp_file, bitmap_info->biWidth, bitmap_info->biHeight, width, height);
+
+	/* if biHeight is positive, the bitmap is a bottom-up DIB */
+	for(i=0; i<height; i++)
+	{
+		p_addr=d_addr+(height-1-i)*bitmap_info->biWidth*bpp_bytes;
+		memcpy(fb_addr, p_addr, bpp_bytes*width);
+		fb_addr += bpp_bytes * vinfo->xres;
+	}
+
+    munmap(f_addr, statbuf.st_size);
+    close (fd);
+
+    return 0;
+}
+
diff --git a/hal/lcd/fb/makefile b/hal/lcd/fb/makefile
new file mode 100644
index 0000000..0b48c53
--- /dev/null
+++ b/hal/lcd/fb/makefile
@@ -0,0 +1,43 @@
+#********************************************************************************
+#      Copyright:  (C) 2023 LingYun IoT System Studio
+#                  All rights reserved.
+#
+#       Filename:  Makefile
+#    Description:  This file used to compile all the C file to respective binary,
+#                  and it will auto detect cross compile or local compile.
+#
+#        Version:  1.0.0(11/08/23)
+#         Author:  Guo Wenxue <guowenxue@gmail.com>
+#      ChangeLog:  1, Release initial version on "11/08/23 16:18:43"
+#
+#*******************************************************************************
+
+PWD=$(shell pwd)
+INSTPATH=/tftp
+
+CROSS_COMPILE=arm-linux-gnueabihf-
+CC=${CROSS_COMPILE}gcc
+
+SRCS = $(wildcard ${VPATH}/*.c)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+SRCFILES = $(wildcard *.c)
+BINARIES=$(SRCFILES:%.c=%)
+
+all: binaries install
+
+binaries:  ${BINARIES}
+
+%:  %.c
+	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
+install:
+	cp $(BINARIES) ${INSTPATH}
+
+clean:
+	@rm -f *.o *.lo $(BINARIES)
+
+distclean: clean
+	@rm -f  tags cscope*
+
+.PHONY: clean entry
diff --git a/hal/lcd/lvgl/libs_lvgl/build.sh b/hal/lcd/lvgl/libs_lvgl/build.sh
new file mode 100755
index 0000000..f3fc658
--- /dev/null
+++ b/hal/lcd/lvgl/libs_lvgl/build.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+PRJ_PATH=`pwd`
+BOARD=imx6ull
+
+LYFTP_SRC=http://master.weike-iot.com:2211/src/
+
+LIB_LVGL=lvgl-8.0.2 
+LIB_LVGL_DRV=lv_drivers-8.0.1
+LIB_LVGL_DEMO=lv_demos-8.0.1
+
+LIBS_DIR="lvgl lv_drivers lv_demos"
+
+CROSS_COMPILE=arm-linux-gnueabihf-
+if [ $# == 1 ] ; then
+   CROSS_COMPILE=$1
+fi
+
+set -e
+
+function prepare_lib()
+{
+    PACK_SUFIX=tar.gz
+    PACK_NAME=$1
+    DIR_NAME=$2
+
+    if [ ! -d ${DIR_NAME} ] ; then
+       if [ ! -s ${PACK_NAME}.${PACK_SUFIX} ] ; then
+          wget ${LYFTP_SRC}/${PACK_NAME}.${PACK_SUFIX}
+       fi 
+
+       tar -xzf ${PACK_NAME}.${PACK_SUFIX} 
+       patch -p0 < patches/${PACK_NAME}-${BOARD}.patch
+       mv ${PACK_NAME} ${DIR_NAME} 
+
+       cd ${DIR_NAME}
+       sed -i -e "s|.*CMAKE_C_COMPILER.*|set(CMAKE_C_COMPILER \"${CROSS_COMPILE}gcc\")|g" CMakeLists.txt
+         temp_file=`ls *_template.h`
+         conf_file=`echo ${temp_file/_template/}`
+         cp ${temp_file} ../${conf_file}
+       cd ${PRJ_PATH}
+    fi
+}
+
+if [[ $# == 1 && $1 == clean ]] ; then
+    rm -rf lv*
+    rm -rf libs
+    exit;
+fi
+
+prepare_lib ${LIB_LVGL} lvgl
+prepare_lib ${LIB_LVGL_DRV} lv_drivers
+prepare_lib ${LIB_LVGL_DEMO} lv_demos
+
+
+mkdir -p ${PRJ_PATH}/libs
+
+for lib in ${LIBS_DIR}
+do
+    if [ -f ${PRJ_PATH}/libs/lib${lib}.a ] ; then
+        continue;
+    fi
+
+    mkdir -p ${lib}/build 
+    cd ${lib}/build/
+    rm -rf * && cmake .. && make
+
+    cp lib*.a ${PRJ_PATH}/libs/lib${lib}.a
+    cd ${PRJ_PATH}
+done
+    
+
diff --git a/hal/lcd/lvgl/libs_lvgl/patches/gen_patch.sh b/hal/lcd/lvgl/libs_lvgl/patches/gen_patch.sh
new file mode 100755
index 0000000..acf88f1
--- /dev/null
+++ b/hal/lcd/lvgl/libs_lvgl/patches/gen_patch.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+# Description: This shell script used to generate patch file
+#      Author: guowenxue <guowenxue@gmail.com>
+#     Version: 1.0.0  
+
+PROJ_PATH=`pwd`
+
+PATCH_PATH=${PROJ_PATH}/patches
+
+BOARD=imx6ull
+PATCH_SUFFIX=${BOARD}.patch
+
+set -e
+
+
+if [ $# != 1 ] ; then
+    echo "Usage: $0 [src_path]"
+    printf "\nExample: \n"
+    echo "$0 lvgl-8.0.2"
+
+    exit ;
+fi
+
+
+SRC=`basename $1`
+
+if [ ! -d ${SRC} ] ; then
+    printf "\nERROR: ${SRC} source code not exist, exit now\n\n"
+    exit
+fi
+
+if [ ! -f ${SRC}.tar.gz ] ; then
+    printf "\nERROR: ${SRC}.tar.gz packet not exist, exit now\n\n"
+    exit
+fi
+
+rm -rf ${SRC}/build
+
+# rename new source code
+mv ${SRC} ${SRC}-${BOARD}
+
+# decompress orignal soruce code packet
+tar -xzf ${SRC}.tar.gz
+
+set +e
+
+# generate patch file 
+diff -Nuar ${SRC} ${SRC}-${BOARD} > ${SRC}-${PATCH_SUFFIX}
+
+# remove orignal soruce code
+rm -rf ${SRC}
+
+# recover new source code
+mv ${SRC}-${BOARD} ${SRC} 
+
diff --git a/hal/lcd/lvgl/libs_lvgl/patches/lv_demos-8.0.1-imx6ull.patch b/hal/lcd/lvgl/libs_lvgl/patches/lv_demos-8.0.1-imx6ull.patch
new file mode 100644
index 0000000..b07ea04
--- /dev/null
+++ b/hal/lcd/lvgl/libs_lvgl/patches/lv_demos-8.0.1-imx6ull.patch
@@ -0,0 +1,49 @@
+diff -Nuar lv_demos-8.0.1/CMakeLists.txt lv_demos-8.0.1-imx6ull/CMakeLists.txt
+--- lv_demos-8.0.1/CMakeLists.txt	2021-06-14 20:00:00.000000000 +0800
++++ lv_demos-8.0.1-imx6ull/CMakeLists.txt	2021-09-27 21:26:45.823935469 +0800
+@@ -1,2 +1,5 @@
++set(CMAKE_C_COMPILER "/opt/buildroot/cortex-a7/bin/arm-linux-gcc") 
++include_directories(..)
++
+ file(GLOB_RECURSE SOURCES src/*.c)
+ add_library(lv_examples STATIC ${SOURCES})
+diff -Nuar lv_demos-8.0.1/lv_demo_conf_template.h lv_demos-8.0.1-imx6ull/lv_demo_conf_template.h
+--- lv_demos-8.0.1/lv_demo_conf_template.h	2021-06-14 20:00:00.000000000 +0800
++++ lv_demos-8.0.1-imx6ull/lv_demo_conf_template.h	2021-09-27 20:57:35.667901897 +0800
+@@ -7,7 +7,7 @@
+  * COPY THIS FILE AS lv_demo_conf.h
+  */
+ 
+-#if 0 /*Set it to "1" to enable the content*/
++#if 1 /*Set it to "1" to enable the content*/
+ 
+ #ifndef LV_EX_CONF_H
+ #define LV_EX_CONF_H
+@@ -25,22 +25,22 @@
+  *********************/
+ 
+ /*Show some widget*/
+-#define LV_USE_DEMO_WIDGETS        0
++#define LV_USE_DEMO_WIDGETS        1
+ #if LV_USE_DEMO_WIDGETS
+ #define LV_DEMO_WIDGETS_SLIDESHOW  0
+ #endif
+ 
+ /*Printer demo, optimized for 800x480*/
+-#define LV_USE_DEMO_PRINTER     0
++#define LV_USE_DEMO_PRINTER     1
+ 
+ /*Demonstrate the usage of encoder and keyboard*/
+-#define LV_USE_DEMO_KEYPAD_AND_ENCODER     0
++#define LV_USE_DEMO_KEYPAD_AND_ENCODER     1
+ 
+ /*Benchmark your system*/
+-#define LV_USE_DEMO_BENCHMARK   0
++#define LV_USE_DEMO_BENCHMARK   1
+ 
+ /*Stress test for LVGL*/
+-#define LV_USE_DEMO_STRESS      0
++#define LV_USE_DEMO_STRESS      1
+ 
+ /*Music player demo*/
+ #define LV_USE_DEMO_MUSIC      1
diff --git a/hal/lcd/lvgl/libs_lvgl/patches/lv_drivers-8.0.1-imx6ull.patch b/hal/lcd/lvgl/libs_lvgl/patches/lv_drivers-8.0.1-imx6ull.patch
new file mode 100644
index 0000000..fddbfea
--- /dev/null
+++ b/hal/lcd/lvgl/libs_lvgl/patches/lv_drivers-8.0.1-imx6ull.patch
@@ -0,0 +1,103 @@
+diff -Nuar lv_drivers-8.0.1/CMakeLists.txt lv_drivers-8.0.1-imx6ull/CMakeLists.txt
+--- lv_drivers-8.0.1/CMakeLists.txt	2021-06-14 19:54:20.000000000 +0800
++++ lv_drivers-8.0.1-imx6ull/CMakeLists.txt	2021-09-27 22:20:38.179997474 +0800
+@@ -1,2 +1,5 @@
++set(CMAKE_C_COMPILER "/opt/buildroot/cortex-a7/bin/arm-linux-gcc") 
++include_directories(..)
++
+ file(GLOB_RECURSE SOURCES ./*.c)
+ add_library(lv_drivers STATIC ${SOURCES})
+diff -Nuar lv_drivers-8.0.1/indev/evdev.c lv_drivers-8.0.1-imx6ull/indev/evdev.c
+--- lv_drivers-8.0.1/indev/evdev.c	2021-06-14 19:54:20.000000000 +0800
++++ lv_drivers-8.0.1-imx6ull/indev/evdev.c	2021-09-27 22:25:04.172002576 +0800
+@@ -115,7 +115,7 @@
+  * @param data store the evdev data here
+  * @return false: because the points are not buffered, so no more data to be read
+  */
+-bool evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
++void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
+ {
+     struct input_event in;
+ 
+@@ -196,7 +196,7 @@
+ 		}
+ 		evdev_key_val = data->key;
+ 		evdev_button = data->state;
+-		return false;
++		return;
+ 	    }
+         }
+     }
+@@ -205,10 +205,10 @@
+         /* No data retrieved */
+         data->key = evdev_key_val;
+ 	data->state = evdev_button;
+-	return false;
++	return;
+     }
+     if(drv->type != LV_INDEV_TYPE_POINTER)
+-        return false;
++        return;
+     /*Store the collected data*/
+ 
+ #if EVDEV_CALIBRATE
+@@ -225,12 +225,12 @@
+       data->point.x = 0;
+     if(data->point.y < 0)
+       data->point.y = 0;
+-    if(data->point.x >= drv->disp->driver.hor_res)
+-      data->point.x = drv->disp->driver.hor_res - 1;
+-    if(data->point.y >= drv->disp->driver.ver_res)
+-      data->point.y = drv->disp->driver.ver_res - 1;
++    if(data->point.x >= drv->disp->driver->hor_res)
++      data->point.x = drv->disp->driver->hor_res - 1;
++    if(data->point.y >= drv->disp->driver->ver_res)
++      data->point.y = drv->disp->driver->ver_res - 1;
+ 
+-    return false;
++    return;
+ }
+ 
+ /**********************
+diff -Nuar lv_drivers-8.0.1/indev/evdev.h lv_drivers-8.0.1-imx6ull/indev/evdev.h
+--- lv_drivers-8.0.1/indev/evdev.h	2021-06-14 19:54:20.000000000 +0800
++++ lv_drivers-8.0.1-imx6ull/indev/evdev.h	2021-09-27 22:25:33.424003137 +0800
+@@ -57,7 +57,7 @@
+  * @param data store the evdev data here
+  * @return false: because the points are not buffered, so no more data to be read
+  */
+-bool evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data);
++void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data);
+ 
+ 
+ /**********************
+diff -Nuar lv_drivers-8.0.1/lv_drv_conf_template.h lv_drivers-8.0.1-imx6ull/lv_drv_conf_template.h
+--- lv_drivers-8.0.1/lv_drv_conf_template.h	2021-06-14 19:54:20.000000000 +0800
++++ lv_drivers-8.0.1-imx6ull/lv_drv_conf_template.h	2021-09-27 22:20:38.183997474 +0800
+@@ -7,7 +7,7 @@
+  * COPY THIS FILE AS lv_drv_conf.h
+  */
+ 
+-#if 0 /*Set it to "1" to enable the content*/
++#if 1 /*Set it to "1" to enable the content*/
+ 
+ #ifndef LV_DRV_CONF_H
+ #define LV_DRV_CONF_H
+@@ -272,7 +272,7 @@
+  *  Linux frame buffer device (/dev/fbx)
+  *-----------------------------------------*/
+ #ifndef USE_FBDEV
+-#  define USE_FBDEV           0
++#  define USE_FBDEV           1
+ #endif
+ 
+ #if USE_FBDEV
+@@ -386,7 +386,7 @@
+  * Mouse or touchpad as evdev interface (for Linux based systems)
+  *------------------------------------------------*/
+ #ifndef USE_EVDEV
+-#  define USE_EVDEV           0
++#  define USE_EVDEV           1
+ #endif
+ 
+ #ifndef USE_BSD_EVDEV
diff --git a/hal/lcd/lvgl/libs_lvgl/patches/lvgl-8.0.2-imx6ull.patch b/hal/lcd/lvgl/libs_lvgl/patches/lvgl-8.0.2-imx6ull.patch
new file mode 100644
index 0000000..5ae5a78
--- /dev/null
+++ b/hal/lcd/lvgl/libs_lvgl/patches/lvgl-8.0.2-imx6ull.patch
@@ -0,0 +1,92 @@
+diff -Nuar lvgl-8.0.2/CMakeLists.txt lvgl-8.0.2-imx6ull/CMakeLists.txt
+--- lvgl-8.0.2/CMakeLists.txt	2021-07-16 23:40:51.000000000 +0800
++++ lvgl-8.0.2-imx6ull/CMakeLists.txt	2021-09-27 22:30:20.360008641 +0800
+@@ -1,3 +1,7 @@
++
++set(CMAKE_C_COMPILER "/opt/buildroot/cortex-a7/bin/arm-linux-gcc")
++include_directories(..)
++
+ if(ESP_PLATFORM)
+ 
+ file(GLOB_RECURSE SOURCES src/*.c)
+diff -Nuar lvgl-8.0.2/lv_conf_template.h lvgl-8.0.2-imx6ull/lv_conf_template.h
+--- lvgl-8.0.2/lv_conf_template.h	2021-07-16 23:40:51.000000000 +0800
++++ lvgl-8.0.2-imx6ull/lv_conf_template.h	2021-09-27 22:33:47.448012614 +0800
+@@ -7,7 +7,7 @@
+  * COPY THIS FILE AS `lv_conf.h` NEXT TO the `lvgl` FOLDER
+  */
+ 
+-#if 0 /*Set it to "1" to enable content*/
++#if 1 /*Set it to "1" to enable content*/
+ 
+ #ifndef LV_CONF_H
+ #define LV_CONF_H
+@@ -21,7 +21,7 @@
+  *====================*/
+ 
+ /*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
+-#define LV_COLOR_DEPTH     32
++#define LV_COLOR_DEPTH     16
+ 
+ /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/
+ #define LV_COLOR_16_SWAP   0
+@@ -42,7 +42,7 @@
+ #define LV_MEM_CUSTOM      0
+ #if LV_MEM_CUSTOM == 0
+ /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
+-#  define LV_MEM_SIZE    (32U * 1024U)          /*[bytes]*/
++#  define LV_MEM_SIZE    (128U * 1024U)          /*[bytes]*/
+
+ /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
+ #  define LV_MEM_ADR          0     /*0: unused*/
+@@ -68,9 +68,10 @@
+ 
+ /*Use a custom tick source that tells the elapsed time in milliseconds.
+  *It removes the need to manually update the tick with `lv_tick_inc()`)*/
+-#define LV_TICK_CUSTOM     0
++#define LV_TICK_CUSTOM     1
+ #if LV_TICK_CUSTOM
+-#define LV_TICK_CUSTOM_INCLUDE  "Arduino.h"         /*Header for the system time function*/
++extern uint32_t millis(void);
++#define LV_TICK_CUSTOM_INCLUDE      <stdint.h>      /*Header for the system time function*/
+ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis())     /*Expression evaluating to current system time in ms*/
+ #endif   /*LV_TICK_CUSTOM*/
+ 
+@@ -137,7 +138,7 @@
+  *-----------*/
+ 
+ /*Enable the log module*/
+-#define LV_USE_LOG      0
++#define LV_USE_LOG      1
+ #if LV_USE_LOG
+ 
+ /*How important log should be added:
+@@ -151,7 +152,7 @@
+ 
+ /*1: Print the log with 'printf';
+  *0: User need to register a callback with `lv_log_register_print_cb()`*/
+-#  define LV_LOG_PRINTF   0
++#  define LV_LOG_PRINTF   1
+ 
+ /*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/
+ #  define LV_LOG_TRACE_MEM            1
+@@ -262,13 +263,13 @@
+ 
+ /*Montserrat fonts with ASCII range and some symbols using bpp = 4
+  *https://fonts.google.com/specimen/Montserrat*/
+-#define LV_FONT_MONTSERRAT_8     0
+-#define LV_FONT_MONTSERRAT_10    0
+-#define LV_FONT_MONTSERRAT_12    0
++#define LV_FONT_MONTSERRAT_8     1
++#define LV_FONT_MONTSERRAT_10    1
++#define LV_FONT_MONTSERRAT_12    1
+ #define LV_FONT_MONTSERRAT_14    1
+-#define LV_FONT_MONTSERRAT_16    0
+-#define LV_FONT_MONTSERRAT_18    0
+-#define LV_FONT_MONTSERRAT_20    0
++#define LV_FONT_MONTSERRAT_16    1
++#define LV_FONT_MONTSERRAT_18    1
++#define LV_FONT_MONTSERRAT_20    1
+ #define LV_FONT_MONTSERRAT_22    0
+ #define LV_FONT_MONTSERRAT_24    0
+ #define LV_FONT_MONTSERRAT_26    0
diff --git a/hal/lcd/lvgl/lvgl_demo.c b/hal/lcd/lvgl/lvgl_demo.c
new file mode 100644
index 0000000..f7eeb5c
--- /dev/null
+++ b/hal/lcd/lvgl/lvgl_demo.c
@@ -0,0 +1,91 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2021 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  lvgl_demo.c
+ *    Description:  This file is LVGL demo program.
+ *                 
+ *        Version:  1.0.0(2021年09月27日)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "2021年09月27日 22时16分52秒"
+ *                 
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "lvgl/lvgl.h"
+#include "lv_drivers/display/fbdev.h"
+#include "lv_drivers/indev/evdev.h"
+#include "lv_demos/lv_demo.h"
+
+#define DISP_BUF_SIZE (128 * 1024)
+
+
+int main(void)
+{
+    lv_disp_drv_t               disp_drv;
+    lv_indev_drv_t              indev_drv;
+    static lv_color_t           buf[DISP_BUF_SIZE]; /* buffer for LVGL to draw the screen's content */
+    static lv_disp_draw_buf_t   disp_buf; /* Initialize a descriptor for the buffer */
+
+    /* LVGL context init */
+    lv_init();
+
+    /* Linux frame buffer device init */
+    fbdev_init();
+
+    /* linux touchscreen device init */
+    lv_indev_drv_init(&indev_drv);
+    indev_drv.type =LV_INDEV_TYPE_POINTER;
+    indev_drv.read_cb =evdev_read;
+    lv_indev_drv_register(&indev_drv);
+
+    /* Initialize and register a display driver */
+    lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);
+    lv_disp_drv_init(&disp_drv);
+    disp_drv.draw_buf   = &disp_buf;
+    disp_drv.flush_cb = fbdev_flush;
+    disp_drv.hor_res    = 800;
+    disp_drv.ver_res    = 480;
+    lv_disp_drv_register(&disp_drv);
+
+    /* Create a Demo */
+    //lv_demo_widgets();
+    lv_demo_music();
+    //lv_demo_keypad_encoder();
+    //lv_demo_stress();
+
+    /* Handle LitlevGL tasks (tickless mode) */
+    while(1) {
+        lv_task_handler();
+        usleep(5000);
+    }
+
+    return 0;
+}
+
+/* Set in lv_conf.h as LV_TICK_CUSTOM_SYS_TIME_EXPR */
+uint32_t millis(void)
+{
+    static uint64_t start_ms = 0;
+    struct timeval tv_start;
+    struct timeval tv_now;
+    uint64_t now_ms;
+    uint32_t time_ms;
+
+    if(start_ms == 0) 
+    {
+        gettimeofday(&tv_start, NULL);
+        start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
+    }
+
+    gettimeofday(&tv_now, NULL);
+    now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
+
+    time_ms = now_ms - start_ms;
+    return time_ms;
+}
diff --git a/hal/lcd/lvgl/makefile b/hal/lcd/lvgl/makefile
new file mode 100644
index 0000000..fc31e3b
--- /dev/null
+++ b/hal/lcd/lvgl/makefile
@@ -0,0 +1,46 @@
+
+CROSS_COMPILE=arm-linux-gnueabihf-
+CC=${CROSS_COMPILE}gcc
+
+CFLAGS = -Wall -Wshadow -Wundef -Wmaybe-uninitialized
+CFLAGS += -O3 -g3 -I./ -I ./libs_lvgl/
+
+LDFLAGS+=-L ./libs_lvgl/libs/ -llv_demos -llv_drivers -llvgl
+
+BIN = lvgl_demo
+
+MAINSRC = lvgl_demo.c
+
+VPATH = 
+OBJEXT ?= .o
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
+OBJS = $(AOBJS) $(COBJS)
+
+## MAINOBJ -> OBJFILES
+
+all: libs clean default 
+	cp ${BIN} /tftp
+
+libs:
+	cd libs_lvgl && ./build.sh ${CROSS_COMPILE}
+
+%.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)
+
+distclean: clean
+	rm -rf cscope* tags
+	cd libs_lvgl && ./build.sh clean
+	

--
Gitblit v1.9.1