国民技术
直播中

jf_1137202360

8年用户 1362经验值
擅长:嵌入式技术
私信 关注
[经验]

【国民技术N32项目移植】LVGL移植

LVGL2.zip (5.27 MB)
(下载次数: 19, 2022-12-26 09:59 上传)
LVGL1.zip (20 MB)
(下载次数: 23, 2022-12-26 09:59 上传)

分别改名字为LVGL.zip.001和LVGL.zip.00解压
打开projectsn32g45x_EVALexamplesUSARTPrintfMDK-ARMPrintf.uvprojx即可。

前言

   前一篇我们完成了TFT的驱动,这一篇我们就可以开始LVGL的移植了。
参考《【国民技术N32项目移植】驱动SPI接口TFT屏》
https://bbs.elecfans.com/jishu_2325154_1_1.html

准备

git clone https://github.com/lvgl/lvgl.git
下载代码到Src目录下
移植过程

配置文件lv_conf.h
复制
lvgl/lv_conf_template.h
改名字为lv_conf.h
#if 0改为1,即直接#include “lv_conf.h”
lv_conf.h添加到工程头文件包含路径。
底层驱动模板
lvgl/examples/porting
下有对应的模板文件,分别是显示,文件系统和输入设备的驱动模板。
lv_port_disp_template.c/h
lv_port_fs_template.c/h
lv_port_indev_template.c/h
暂时只移植显示,所以复制lv_port_disp_template.c/hsrc
改名字为
lv_port_disp.c/h
.c.h里面的#if 0改为1
.c#include "lv_port_disp_template.h"改为#include "lv_port_disp.h"
HAL层模板
lvgl/src/hal
我们直接使用不修改
lv_hal_disp.c/h
lv_hal_indev.c/h
lv_hal_tick.c/h
lv_hal.h
添加文件
如下
srccore下所有文件
srcdraw下所有文件和sw子文件夹
srcfont下所有文件
srchal下所有文件
srclayouts所有子文件夹文件
srclibs所有子文件夹文件
srcmisc下所有文件
srcothers所有子文件夹文件
srcthemes下所有文件和所有子文件夹
srcwidgets所有子文件夹文件
图片1.png
需要移植的代码
移植比较简单,直接使用底层驱动模板根据实际实现修改lv_port_disp.c,并配置lv_conf.h即可。
头文件包含模式
需要在工程中定义宏
#define LV_LVGL_H_INCLUDE_SIMPLE 1
这样需要将lvgl.h所在路径配置为工程头文件包含路径。
代码中直接#include "lvgl.h"即可
否则是#include "../../lvgl.h"
图片2.png
分辨率配置
lv_port_disp.h
#define MY_DISP_HOR_RES 240
#define MY_DISP_VER_RES 240
初始化
lv_port_disp.c
实现disp_init
即调用自己的初始化函数,如果在其他地方初始化了,该函数实现为空函数体即可。
缓冲区
lv_port_disp.c
lv_port_disp_init
注释掉/* Example for 2) */
/* Example for 3) also set disp_drv.full_refresh = 1 below*/对应的代码
使用/* Example for 1) */
lv_port_disp_init
函数调用disp_init实现初始化
刷新显示
lv_port_disp.c包含#include "lcd.h"
disp_flush
/*put_px(x, y, color_p)/改为
lcd_draw_point(x,y,color_p->full);
颜色深度
lv_conf.h
#define LV_COLOR_DEPTH 16
typedef LV_CONCAT3(lv_color, LV_COLOR_DEPTH, _t) lv_color_t;
lv_color_t类型为lv_color_16_t
堆大小配置
lv_conf.h
#define LV_MEM_SIZE (10U * 1024U) /* [bytes] */
按需提供堆大小,过大可能编译不过,过小可能影响创建对象。
时间滴答
如果在lv_conf.h中指定LV_TICK_CUSTOM1则需要用户提供相关接口
LV_TICK_CUSTOM_SYS_TIME_EXPR用于获取当前毫秒值
和头文件LV_TICK_CUSTOM_INCLUDE
否则使用lvgl/src/hal/lv_hal_tick.c的实现
每隔x毫秒调用lv_tick_inc(x),使用内部计数器定时。
周期调用lv_tick_inc更新时间滴答,比如专门硬件定时器回调调用,如果1ms周期则
lv_tick_inc(1);
这里使用systick
main.c中
#include "lvgl.h"
          /* PA2  */
          RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA,ENABLE);
    GPIO_InitStructure.Pin        =  GPIO_PIN_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
          GPIO_SetBits(GPIOA, GPIO_PIN_2);
void SysTick_Handler(void)
{
        lv_tick_inc(1);
        if(GPIO_ReadOutputDataBit(GPIOA, GPIO_PIN_2))
        {
                        GPIO_ResetBits(GPIOA, GPIO_PIN_2);
        }
        else
  {
                  GPIO_SetBits(GPIOA, GPIO_PIN_2);
        }
}
注释掉n32g45x_it.c中的
/**
* @Brief  This function handles SysTick Handler.
*/
//void SysTick_Handler(void)
//{
//}
初始化
                SysTick_Config(144000);
                NVIC_EnableIRQ(SysTick_IRQn);
以上使用PA2sysyick中断中翻转,测试定时是否正确
逻辑分析仪测试PA2看到非常准确
图片3.png
日志
lv_conf.h
#define LV_USE_LOG 0
改为
#define LV_USE_LOG 1使能日志
#define LV_LOG_LEVEL LV_LOG_LEVEL_TRACE设置日志,等级
LV_LOG_LEVEL_TRACE表示所有信息都打印
如果#define LV_LOG_PRINTF 0
则需要调用设置lv_log_register_print_cb()打印函数
否则使用printf
#define LV_LOG_USE_TIMESTAMP 1
使能打印时间
其他的模块打印使能
字体配置
lv_conf.h
中按需使能对应的字体,如果有对应编译错误信息根据提示使能
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_14 1
#define LV_FONT_MONTSERRAT_16 1
工程配置
使用gnu11
图片4.png
如果提示.ObjectsPrintf.axf: Error: L6218E: Undefined symbol __aeabi_assert (referred from qrcodegen.o).
则可以不勾选Use MicroLIB
图片5.png
或者勾选了则自己实现
__aeabi_assert函数
__attribute__((weak))
void abort(void) {
  for (;;);
}
__attribute__((weak,noreturn))
void __aeabi_assert (const char *expr, const char *file, int line) {
  char str[12], *p;
  fputs("*** assertion failed: ", stderr);
  fputs(expr, stderr);
  fputs(", file ", stderr);
  fputs(file, stderr);
  fputs(", line ", stderr);
  p = str + sizeof(str);
  *--p = '';
  *--p = 'n';
  while (line > 0) {
    *--p = '0' + (line % 10);
    line /= 10;
  }
  fputs(p, stderr);
  abort();
}
测试
static void btn_event_cb(lv_event_t * e)
{
        lv_event_code_t code = lv_event_get_code(e);
        lv_obj_t * btn = lv_event_get_target(e);
        if(code == LV_EVENT_CLICKED) {
                static uint8_t cnt = 0;
                cnt++;
                /*Get the first child of the button which is the label and change its text*/
                lv_obj_t * label = lv_obj_get_child(btn, 0);
                lv_label_set_text_fmt(label, "Button: %d", cnt);
                }
}
/**
        Create a button with a label and react on click event.
*/
void lv_example_get_started_1(void)
{
                lv_color_t color;
                color.full=(uint16_t)0xF800;
                lv_obj_t * btn = lv_btn_create(lv_scr_act());                /*Add a button the current screen*/
                lv_obj_set_style_text_font(btn, &lv_font_montserrat_24 ,0);
                lv_obj_set_style_text_color(btn,color,0);
                lv_obj_set_pos(btn, 120-100, 120-50);         /*Set its position*/
                lv_obj_set_size(btn, 200, 100);         /*Set its size*/
                lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);        /*Assign a callback to the button*/
                lv_obj_t * label = lv_label_create(btn);        /*Add a label to the button*/
                lv_label_set_text(label, "Hello LVGL");                /*Set the labels text*/
                lv_obj_center(label);
}
main函数中
                lv_init();
                lv_port_disp_init();
                lv_example_get_started_1();
    while (1)
    {
                        lv_task_handler();
    }
lcd_conf.h中需要#define LV_FONT_MONTSERRAT_24 1
图片6.png
Demos
添加demos文件在到头文件包含路径
图片7.png
添加Demos文件
图片8.png
lv_conf.h中配置
#define LV_BUILD_EXAMPLES 1  
#define LV_FONT_MONTSERRAT_22 1
main.c
#include "lv_demos.h"
lv_demo_widgets();
MUSIC
lv_conf.h
/*Music player demo*/
#define LV_USE_DEMO_MUSIC 1
#if LV_USE_DEMO_MUSIC
    #define LV_DEMO_MUSIC_SQUARE    1
    #define LV_DEMO_MUSIC_LANDSCAPE 1
    #define LV_DEMO_MUSIC_ROUND     1
    #define LV_DEMO_MUSIC_LARGE     1
    #define LV_DEMO_MUSIC_AUTO_PLAY 1
#endif
Main
lv_demo_music();
由于存储空间不够未能测试。
WIDGETS
lv_conf.h
#define LV_MEM_SIZE (48U * 1024U)          /*[bytes]*/
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
#define LV_USE_DEMO_WIDGETS 1
#if LV_USE_DEMO_WIDGETS
    #define LV_DEMO_WIDGETS_SLIDESHOW 1
#endif
Main
lv_demo_music();
lv_demo_widgets();
图片9.png
STRESS
lv_conf.h
/*Stress test for LVGL*/
#define LV_USE_DEMO_STRESS 1
Main
lv_demo_stress();
图片10.png
BENCHMARK
lv_conf.h
#define LV_USE_FONT_COMPRESSED 1
/*Benchmark your system*/
#define LV_USE_DEMO_BENCHMARK 1
#if LV_USE_DEMO_BENCHMARK
    /*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/
    #define LV_DEMO_BENCHMARK_RGB565A8 1
#endif
Main
lv_demo_benchmark(LV_DEMO_BENCHMARK_MODE_RENDER_AND_DRIVER);
图片11.png
KEYPAD
lv_conf.h
/*Demonstrate the usage of encoder and keyboard*/
#define LV_USE_DEMO_KEYPAD_AND_ENCODER 1
Main
lv_demo_keypad_encoder();
图片12.png
LAYOPUT
lv_conf.h
/*Flex layout demo*/
#define LV_USE_DEMO_FLEX_LAYOUT 1
Main
lv_demo_flex_layout();
图片13.png
总结
   以上从驱动开始,详细的介绍了LVGL的移植过程。得益于MCU比较高的性能,所以GUI的操作都比较流畅。并且得益于完善的外设库,文档也比较全,使得移植过程加快。

更多回帖

发帖
×
20
完善资料,
赚取积分