linguanghua 发表于 2021-8-12 15:19

AC781X开发板移植littlevGL(LVGL)

本帖最后由 linguanghua 于 2021-9-1 16:13 编辑

上次移植过单色屏的GUI到AC781X开发板,现在找个彩屏,移植littlevGL(选择叫LVGL)。这个GUI版本更新很快,我最初使用是2019年,那时候国内很少人使用,现在已经更新到8.0版本了,已经很流行了,而原来的API已经面目全非。V7中的原来自带的task任务系统变成V8中的timer,不过本质上是一样的,定时调用。

0.开始移植,准备一个可正常使用的工程,包含LCD驱动。工程目录新建文件夹“LVGL”。

1.下载LVGL代码。目前最新V8.1了。
源码:https://github.com/lvgl/lvgl
官网:https://lvgl.io/
2.文档lvgl-master解压,复制文件夹“src”,文件lvgl.h和lv_conf_template.h 到文件夹“LVGL”,复制 examples下porting文件夹到文件夹“LVGL”。
3.文件夹“LVGL”下,将lv_conf_template.h改名为lv_conf.h,此文件内部,将开头的 #if 0 改为 #if 1,#define LV_COLOR_DEPTH   16这里修改为LCD位深。
此文件内有许多宏定义,可开关特定的功能、性能。
4.将lv_port_disp_template.c改名lv_port_disp.c,对应.H文件名也要修改。
lv_port_disp.c修改如下:(不知道为什么显示不了)
/**
* @file lv_port_disp_templ.c
*
*/

/*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
#if 1

/*********************
*      INCLUDES
*********************/
#include "lv_port_disp.h"
#include "../../lvgl.h"
#include "lcd.h"

/*********************
*      DEFINES
*********************/

/**********************
*      TYPEDEFS
**********************/

/**********************
*STATIC PROTOTYPES
**********************/
static void disp_init(void);

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
//      const lv_area_t * fill_area, lv_color_t color);

/**********************
*STATIC VARIABLES
**********************/

/**********************
*      MACROS
**********************/
/* Maximal horizontal and vertical resolution to support by the library.*/
#define MY_DISP_HOR_RES          (160)//320
#define MY_DISP_VER_RES          (128)//480
/**********************
*   GLOBAL FUNCTIONS
**********************/

void lv_port_disp_init(void)
{
    /*-------------------------
   * Initialize your display
   * -----------------------*/
    disp_init();

    /*-----------------------------
   * Create a buffer for drawing
   *----------------------------*/

    /**
   * LVGL requires a buffer where it internally draws the widgets.
   * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
   * The buffer has to be greater than 1 display row
   *
   * There are 3 buffering configurations:
   * 1. Create ONE buffer:
   *      LVGL will draw the display's content here and writes it to your display
   *
   * 2. Create TWO buffer:
   *      LVGL will draw the display's content to a buffer and writes it your display.
   *      You should use DMA to write the buffer's content to the display.
   *      It will enable LVGL to draw the next part of the screen to the other buffer while
   *      the data is being sent form the first buffer. It makes rendering and flushing parallel.
   *
   * 3. Double buffering
   *      Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
   *      This way LVGL will always provide the whole rendered screen in `flush_cb`
   *      and you only need to change the frame buffer's address.
   */

    /* Example for 1) */
    static lv_disp_draw_buf_t draw_buf_dsc_1;
    static lv_color_t buf_1;                        /*A buffer for 10 rows*/
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/


    /*-----------------------------------
   * Register the display in LVGL
   *----------------------------------*/

    static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);                  /*Basic initialization*/

    /*Set up the functions to access to your display*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = MY_DISP_HOR_RES;
    disp_drv.ver_res = MY_DISP_VER_RES;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;

    /*Set a display buffer*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /*Required for Example 3)*/
    //disp_drv.full_refresh = 1

    /* Fill a memory array with a color if you have GPU.
   * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
   * But if you have a different GPU you can use with this callback.*/
    //disp_drv.gpu_fill_cb = gpu_fill;

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

/**********************
*   STATIC FUNCTIONS
**********************/

/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
    /*You code here*/
}

/*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.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

    LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);

    /*IMPORTANT!!!
   *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

/*OPTIONAL: GPU INTERFACE*/

/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
//                  const lv_area_t * fill_area, lv_color_t color)
//{
//    /*It's an example code which should be done by your GPU*/
//    int32_t x, y;
//    dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
//
//    for(y = fill_area->y1; y <= fill_area->y2; y++) {
//      for(x = fill_area->x1; x <= fill_area->x2; x++) {
//            dest_buf = color;
//      }
//      dest_buf+=dest_width;    /*Go to the next line*/
//    }
//}


#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif

5.打开工程文件,添加连个组 lvgl/src 和 lvgl/port ,将各个C文件导入工程。一些字体文件(font)和 extra 内的文件,gpu文件可不用添加,除非使用到。
6.定时器中断函数里加入lv_tick_inc(1);
/**
* @prototype TIM2_IRQnCallBack(uint8_t lparam)
*
* @param ...
* @return         ...
*
* @brief         TIM2 module interrupt handler.
*                         TIM2中断处理函数.
*/
void TIM2_IRQnCallBack(uint8_t lparam)
{
      if (TIMER_GetIntFlag(TIMER2))
    {
      
                g_ctimeflag=1;
      lv_tick_inc(1);
      }
    TIMER_ClrIntFlag(TIMER2);
}

6.在需要的地方添加头文件(如main.c)
#include "lvgl.h"
#include "lv_port_disp.h"

程序开头加入
lv_init();                                                      
    lv_port_disp_init();然后在主函数的死循环或者低优先级任务中加入lv_task_handler();

这样就可以正常使用了。
用的屏幕比较小,不好发挥这个GUI的长处,随便弄些看看效果。在大屏中,这个GUI效果很不错。总体上比emWin好看。





daichaodai 发表于 2021-8-13 21:06

不错,改天也来玩玩。

marginer 发表于 2021-8-20 16:43

硬件上是透过什么连接和控制的。

zsm123 发表于 2021-8-28 20:52

麻烦问下,切屏速度如何? SPI 传输使用 DMA了吗?

另外,帖子中正文处“lv_port_disp.c”的修改源码好像显示异常, 麻烦修改下?
@linguanghua

单片小菜 发表于 2021-9-1 09:31

这个界面确实很棒,改天我也试试,看看怎么搞的。

kkzz 发表于 2021-9-1 19:42

芯片最低要求是什么?   

hudi008 发表于 2021-9-1 19:43

这个mcu是256kb吗      

lzmm 发表于 2021-9-1 19:43

LVGL提供了使用易于使用的图形元素   

minzisc 发表于 2021-9-1 19:43

LVGL中文教程有吗   

selongli 发表于 2021-9-1 19:44

littlevgl是一个小型开源嵌入式 GUI 库

fentianyou 发表于 2021-9-1 19:45

研究一下例程和源码。

xiaoyaodz 发表于 2021-9-1 19:45

设计UI界面太难了   

febgxu 发表于 2021-9-1 19:46

主要参考资料有吗   

sdlls 发表于 2021-9-1 19:47

全库采用纯 c 语言开发

pixhw 发表于 2021-9-1 19:47

刷新的速度快吗   

selongli 发表于 2021-9-1 19:48

7.0版本的改动还是比较大的

minzisc 发表于 2021-9-1 19:48

LVGL爱好者提供资料   

lzmm 发表于 2021-9-1 19:48

lvgl官方的教程是英文的

hudi008 发表于 2021-9-1 19:48

刷新的速度怎么样   

kkzz 发表于 2021-9-1 19:48

占用多大的空间呢      
页: [1] 2 3
查看完整版本: AC781X开发板移植littlevGL(LVGL)