[学习笔记] AC781X开发板移植littlevGL(LVGL)

[复制链接]
13837|58
 楼主| linguanghua 发表于 2021-8-12 15:19 | 显示全部楼层 |阅读模式
本帖最后由 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修改如下:(不知道为什么显示不了)
  1. /**
  2. * [url=home.php?mod=space&uid=288409]@file[/url] lv_port_disp_templ.c
  3. *
  4. */

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

  7. /*********************
  8. *      INCLUDES
  9. *********************/
  10. #include "lv_port_disp.h"
  11. #include "../../lvgl.h"
  12. #include "lcd.h"

  13. /*********************
  14. *      DEFINES
  15. *********************/

  16. /**********************
  17. *      TYPEDEFS
  18. **********************/

  19. /**********************
  20. *  STATIC PROTOTYPES
  21. **********************/
  22. static void disp_init(void);

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

  26. /**********************
  27. *  STATIC VARIABLES
  28. **********************/

  29. /**********************
  30. *      MACROS
  31. **********************/
  32. /* Maximal horizontal and vertical resolution to support by the library.*/
  33. #define MY_DISP_HOR_RES          (160)  //320
  34. #define MY_DISP_VER_RES          (128)  //480
  35. /**********************
  36. *   GLOBAL FUNCTIONS
  37. **********************/

  38. void lv_port_disp_init(void)
  39. {
  40.     /*-------------------------
  41.      * Initialize your display
  42.      * -----------------------*/
  43.     disp_init();

  44.     /*-----------------------------
  45.      * Create a buffer for drawing
  46.      *----------------------------*/

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

  67.     /* Example for 1) */
  68.     static lv_disp_draw_buf_t draw_buf_dsc_1;
  69.     static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                          /*A buffer for 10 rows*/
  70.     lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/


  71.     /*-----------------------------------
  72.      * Register the display in LVGL
  73.      *----------------------------------*/

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

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

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

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

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

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

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

  90.     /*Finally register the driver*/
  91.     lv_disp_drv_register(&disp_drv);
  92. }

  93. /**********************
  94. *   STATIC FUNCTIONS
  95. **********************/

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

  101. /*Flush the content of the internal buffer the specific area on the display
  102. *You can use DMA or any hardware acceleration to do this operation in the background but
  103. *'lv_disp_flush_ready()' has to be called when finished.*/
  104. static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
  105. {
  106.     /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

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

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

  112. /*OPTIONAL: GPU INTERFACE*/

  113. /*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
  114. //static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
  115. //                    const lv_area_t * fill_area, lv_color_t color)
  116. //{
  117. //    /*It's an example code which should be done by your GPU*/
  118. //    int32_t x, y;
  119. //    dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
  120. //
  121. //    for(y = fill_area->y1; y <= fill_area->y2; y++) {
  122. //        for(x = fill_area->x1; x <= fill_area->x2; x++) {
  123. //            dest_buf[x] = color;
  124. //        }
  125. //        dest_buf+=dest_width;    /*Go to the next line*/
  126. //    }
  127. //}


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

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

5.打开工程文件,添加连个组 lvgl/src 和 lvgl/port ,将各个C文件导入工程。一些字体文件(font)和 extra 内的文件,gpu文件可不用添加,除非使用到。
6.定时器中断函数里加入lv_tick_inc(1);
  1. /**
  2. * [url=home.php?mod=space&uid=555622]@prototype[/url] TIM2_IRQnCallBack(uint8_t lparam)
  3. *
  4. * @param[in] ...
  5. * [url=home.php?mod=space&uid=266161]@return[/url]         ...
  6. *
  7. * [url=home.php?mod=space&uid=247401]@brief[/url]           TIM2 module interrupt handler.
  8. *                         TIM2中断处理函数.
  9. */
  10. void TIM2_IRQnCallBack(uint8_t lparam)
  11. {
  12.         if (TIMER_GetIntFlag(TIMER2))
  13.     {
  14.         
  15.                 g_ctimeflag=1;
  16.         lv_tick_inc(1);
  17.         }
  18.     TIMER_ClrIntFlag(TIMER2);
  19. }


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

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

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

IMG_20210811_164316.jpg IMG_20210811_170603.jpg IMG_20210811_170908.jpg IMG_20210812_111416.jpg IMG_20210812_112325.jpg IMG_20210812_113111.jpg



daichaodai 发表于 2021-8-13 21:06 来自手机 | 显示全部楼层
不错,改天也来玩玩。
marginer 发表于 2021-8-20 16:43 | 显示全部楼层
硬件上是透过什么连接和控制的。

评论

SPI接口的LCD屏,连线。  发表于 2021-8-20 17:38
zsm123 发表于 2021-8-28 20:52 | 显示全部楼层
麻烦问下,切屏速度如何? SPI 传输使用 DMA了吗?

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

评论

源码贴上了。 其实这个GUI移植是最容易的。比起EMWIN,GUIX这些。 LVGL现在就差在没有上位机进行布局。  发表于 2021-9-1 16:15
单片小菜 发表于 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 | 显示全部楼层
占用多大的空间呢      
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

221

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部