LVGL学习笔记1 - 准备

news2024/11/20 1:54:20

目录

1. 下载LVGL源代码

2. 平台

3. 导入到工程

3.1 配置头文件

3.2 src文件夹

4. 移植

4.1 显示接口部分

4.1.1 disp_init

4.1.2 lv_port_disp_init

4.1.3 disp_flush

4.2 IPA部分

4.2.1 lv_draw_gd32_ipa_init

4.2.2 lv_draw_gd32_ipa_blend_fill

4.2.3 lv_draw_gd32_ipa_blend_map

4.2.3 lv_gpu_gd32_ipa_wait_cb

4.3 tick

5. 初始化


LVGL是Light and Versatile Graphics Library(轻量级通用型图形库)的简称,遵循MIT开源许可协议。

LVGL的官网地址如下:

LVGL - Light and Versatile Embedded Graphics Library

LVGL中文资料:

http://lvgl.z.net

1. 下载LVGL源代码

源代码在Github上。

LVGL部分:

GitHub - lvgl/lvgl: Powerful and easy-to-use embedded GUI library with many widgets, advanced visual effects (opacity, antialiasing, animations) and low memory requirements (16K RAM, 64K Flash).https://github.com/lvgl/lvgl

驱动部分(这部分和外部驱动芯片有关,例如ST7565之类的,而GD32F450自带驱动,所以实际不需要):

GitHub - lvgl/lv_drivers: TFT and touch pad drivers for LVGL embedded GUI libraryhttps://github.com/lvgl/lv_drivers

2. 平台

平台1:

GD的开发板GD32450I_EVAL,即GD32GD32F450 + 4.3寸480x272。

编译环境是MDK + GCC。

平台2:

Visual Studio模拟器,下载地址:

GitHub - lvgl/lv_port_win_visual_studio: LVGL Windows Simulator Visual Studio Edition

Visual Studio的版本要求是2019版及以上,下载后打开工程LVGL.Simulator.sln,将默认的平台改为X64(根据自己的Windows配置修改),编译后可以运行看看效果。如果只用这个模拟器学习,可以不看后面的GD32F450的移植。

3. 导入到工程

3.1 配置头文件

根目录下的lv_conf_template.h和lvgl.h拷贝到工程中,并将lv_conf_template.h改名为lv_conf.h。

lv_conf.h是会随项目情况改动到的,放在项目相关的目录内,这里做个另外的lv_config.h,里面只是include真正的lv_config.h文件。而lvgl.h不会更改,而且和代码内的包含路径有关,可以保留在原来的相对路径内。

 其中lv_config.h的内容:

#ifndef LV_CONF_H
#define LV_CONF_H

#include "..\..\include.h"

#endif

其中include.h中会include真正的配置文件。

把配置文件中的配置打开,默认有一个宏定义设置为0的,改成1。

3.2 src文件夹

把文件加入MDK的工程,draw文件夹里面还有一些文件夹,可以先不加,和平台移植有关。

4. 移植

draw文件夹中有部分代码和平台有关,这里拷贝分和平台有关的代码,例如stm32_dma2d这个文件夹并改名字为gd32_ipa,里面的文件名改为lv_gpu_gd323_ipa.c和lv_gpu_gd323_ipa.h,将所有的stm32和dma2d的字符串改为gd32和ipa。

搜索LV_USE_GPU_STM32_DMA2D,参照改一个LV_USE_GPU_GD32_IPA,将lv_gpu_gd323_ipa.c中的函数内有关STM32的部分删除。

4.1 显示接口部分

在之前下载的lvgl文件夹里面\examples\porting文件夹下有对应的硬件接口文件lv_port_disp_template.c和lv_port_disp_template.h。这个文件主要要实现函数disp_init、lv_port_disp_init和disp_flush。

4.1.1 disp_init

显示初始化,主要是硬件配置和TLI接口初始化。

要使用到SDRAM,初始化好TLI接口,并且定义好一个Layer。

定义指针变量pTFTBuf指向SDRAM,因为这里定义格式为RGB565,大小为TFT_WIDTH * TFT_HEIGHT * 2字节。

#define GUI_TFT_BUF_START               EXMC_SDRAM_ADDR0
#define GUI_TFT_BUF_LEN                 (TFT_WIDTH * TFT_HEIGHT * sizeof(lv_color_t))
uint16_t *pTFTBuf = (uint16_t *)GUI_TFT_BUF_START;

选择Layer 0作为显示层,初始化这个层。

    tliLayer_t layer;
    layer.alpha = 0xFF;
    layer.bufAddr = (uint32_t)pTFTBuf;
    layer.defalutColor = 0x000000FF;//0x00FFFFFF;
    layer.format = FORMAT_RGB565;
    layer.x = 0;
    layer.y = 0;
    layer.w = TFT_WIDTH;
    layer.h = TFT_HEIGHT;
    tliLayerInit(0, layer, 1);

4.1.2 lv_port_disp_init

这个函数里面需要选择1种显示缓冲,文件提供了3种方式的缓冲方式,方式1/2/3对应的刷新速度分别是慢/中/快,而RAM占用是少/中/多。这里选择方式3,分配的空间放在SDRAM中(这里注意,如果RAM不够会导致Hard Fault中断,我选择方式2会在第四次调用disp_flush后出错)。

#define GUI_DISP_BUF1_START             (GUI_TFT_BUF_START + GUI_TFT_BUF_LEN)
#define GUI_DISP_BUF1_LEN               GUI_TFT_BUF_LEN
#define GUI_DISP_BUF2_START             (GUI_DISP_BUF1_START + GUI_DISP_BUF1_LEN)
#define GUI_DISP_BUF2_LEN               GUI_TFT_BUF_LEN

static lv_disp_draw_buf_t draw_buf_dsc;
static lv_color_t *dispbuf_1 = (lv_color_t *)GUI_DISP_BUF1_START;
static lv_color_t *dispbuf_2 = (lv_color_t *)GUI_DISP_BUF2_START;

lv_disp_draw_buf_init(&draw_buf_dsc, dispbuf_1, dispbuf_2, GUI_DISP_BUF1_LEN);   /*Initialize the display buffer*/

4.1.3 disp_flush

对于GD32F450的TLI来说,flush就是对Layer对应的buffer更新数据。

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*/
    int32_t x;
    int32_t y;
    uint16_t *pTFTBuf = (uint16_t *)GUI_TFT_BUF_START;
    //Printf("draw:(%d, %d) - (%d, %d)\n", area->x1, area->y1, area->x2, area->y2);
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
            /*Put a pixel to the display. For example:*/
            /*put_px(x, y, *color_p)*/
            *(uint16_t *)(pTFTBuf + y * TFT_WIDTH + x) = (*color_p).full;
            color_p++;
        }
    }

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

4.2 IPA部分

4.2.1 lv_draw_gd32_ipa_init

初始化ipa,并设置颜色模式。

void lv_draw_gd32_ipa_init(void)
{
    RCU_AHB1EN |= ((uint32_t)1 << 23);
    //IPA Reset
    RCU_AHB1RST |= ((uint32_t)1 << 23);
    RCU_AHB1RST &= ~((uint32_t)1 << 23);
    
    /*set output colour mode*/
    IPA_CTL |= ((uint32_t)1 << 2);
    IPA_DPCTL = LV_IPA_COLOR_FORMAT;
}

4.2.2 lv_draw_gd32_ipa_blend_fill

这个函数的作用是用指定的颜色刷新显存。函数原型:

static void lv_draw_gd32_ipa_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, 
    const lv_area_t * fill_area, lv_color_t color)

参数含义:

dest_buf - 显存地址

dest_stride - 显存地址偏移量

fill_area - 填充的区域,长方形(x1,y1)- (x2,  y2)

color - 填充的颜色

static void lv_draw_gd32_ipa_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area,
                                           lv_color_t color)
{
    /*Simply fill an area*/
    int32_t area_w = lv_area_get_width(fill_area);
    int32_t area_h = lv_area_get_height(fill_area);
    invalidate_cache();

    IPA_CTL |= ((uint32_t)1 << 2);  //Stop IPA
    
    IPA_CTL &= ~((uint32_t)0x3 << 16);
    IPA_CTL |= ((uint32_t)0x3 << 16);    //Specific color fill
    
    IPA_DMADDR = (uint32_t)dest_buf;
    IPA_DPV = color.full;
    IPA_DLOFF = dest_stride - area_w;
    IPA_IMS = (area_w << 16) | (area_h << 0);
    
    IPA_CTL |= ((uint32_t)1 << 0);
}

4.2.3 lv_draw_gd32_ipa_blend_map

这个函数的作用是指定buffer更新显存。

static void lv_draw_gd32_ipa_blend_map(
    lv_color_t * dest_buf, 
    const lv_area_t * dest_area, 
    lv_coord_t dest_stride,
    const lv_color_t * src_buf, 
    lv_coord_t src_stride, 
    lv_opa_t opa)

参数含义:

dest_buf - 显存地址

dest_area - 填充的区域

dest_stride - 显存地址偏移量

src_buf - 源数据地址

dest_stride - 源数据地址偏移量

opa - alpha值

static void lv_draw_gd32_ipa_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
                                          const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa)
{
    /*Simple copy*/
    int32_t dest_w = lv_area_get_width(dest_area);
    int32_t dest_h = lv_area_get_height(dest_area);
    invalidate_cache();
    
    if(opa >= LV_OPA_MAX) {
        IPA_CTL |= ((uint32_t)1 << 2);  //Stop IPA
    
        IPA_CTL &= ~((uint32_t)0x3 << 16);
        IPA_CTL = ((uint32_t)0x0 << 16);    
        
        IPA_FPCTL = LV_IPA_COLOR_FORMAT;
        IPA_FMADDR = (uint32_t)src_buf;
        IPA_FLOFF = src_stride - dest_w;
        IPA_DMADDR = (uint32_t)dest_buf;
        IPA_DLOFF = dest_stride - dest_w;
        IPA_IMS = (dest_w << 16) | (dest_h << 0);

        IPA_CTL |= ((uint32_t)1 << 0); //Start IPA
    }
    else {
        IPA_CTL |= ((uint32_t)1 << 2);  //Stop IPA
    
        IPA_CTL &= ~((uint32_t)0x3 << 16);
        IPA_CTL |= ((uint32_t)0x2 << 16);  
        IPA_BPCTL = LV_IPA_COLOR_FORMAT;
        IPA_BMADDR = (uint32_t)dest_buf;
        IPA_BLOFF = dest_stride - dest_w;
        IPA_FPCTL = (uint32_t)LV_IPA_COLOR_FORMAT
                         /*alpha mode 2, replace with foreground * alpha value*/
                         | (2 << 16)
                         /*alpha value*/
                         | (opa << 24);
        IPA_FMADDR = (uint32_t)src_buf;
        IPA_FLOFF = src_stride - dest_w;
        IPA_DMADDR = (uint32_t)dest_buf;
        IPA_DLOFF = dest_stride - dest_w;
        IPA_IMS = (dest_w << 16) | (dest_h << 0);
        
        IPA_CTL |= ((uint32_t)1 << 0); //Start IPA
    }
}

4.2.3 lv_gpu_gd32_ipa_wait_cb

这个函数的作用是等待渲染结束。

void lv_gpu_gd32_ipa_wait_cb(lv_draw_ctx_t * draw_ctx)
{
    lv_disp_t * disp = _lv_refr_get_disp_refreshing();
    if(disp->driver && disp->driver->wait_cb) {
        while(IPA_CTL & 0x01) {
            disp->driver->wait_cb(disp->driver);
        }
    }
    else {
        while(IPA_CTL & 0x01);
    }
    lv_draw_sw_wait_for_finish(draw_ctx);
}

4.3 tick

LVGL 需要一个系统滴答来了解动画和其他任务(例如输入设备读取)所用的时间,所以需要在一个定时器中调用lv_tick_inc。

lv_tick_inc(TIMER_MS);

定时调用这个函数即可,实现方式可以随意,裸奔的方式可以在system tick中调用。

5. 初始化

在使用其他LVGL的API前必须调用lv_init(),然后调用lv_port_disp_init即可。

    lv_init();
    lv_port_disp_init();

这时候屏幕应该是没有显示(如果把pTFTBuf 的数据全部改成0xF800,即红色,可以看到屏幕为红色,LVGL并没有起作用)。

在非OS应用中,需要在主循环中添加lv_task_handler();而在OS应用中,应该是在一个任务循环中添加这个函数的调用。

这是屏幕会显示白屏,添加一段测试程序(在lv_port_disp_init()后添加即可)。

lv_obj_t *rect = lv_obj_create(lv_scr_act());
lv_obj_set_size(rect, LV_PCT(20), LV_PCT(20));
lv_obj_align(rect, LV_ALIGN_CENTER, 0, 0);

即画一个矩形。

模拟器显示效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/110662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Web API节点操作

1、节点概述 网页中的所有内容都是节点&#xff08;标签、属性、文本、注释等&#xff09;&#xff0c;在DOM 中&#xff0c;节点使用 node 来表示。HTML DOM 树中的所有节点均可通过 JavaScript 进行访问&#xff0c;所有 HTML 元素&#xff08;节点&#xff09;均可被修改&a…

(JavaP1177 )【模板】快速排序

【模板】快速排序 一、题目描述 利用快速排序算法将读入的 NNN 个数从小到大排序后输出。 快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料&#xff0c;掌握后独立完成。&#xff08;C 选手请不要试图使用 STL&#xff0c;虽然你…

认识信道(零):天线的极化

认识信道(零)&#xff1a;天线的极化 文章目录认识信道(零)&#xff1a;天线的极化零.简述一.平面电磁波的传播二.对于field pattern的研究三.对于传播路程的研究四.极化失配五.传播结果六.QuaDRiGa Tutorial分析TXV-RXVTX45-RXV和 TXV-RX45TX45-RX45TX90-RX0&#xff0c;45&am…

[Linux]-Crontab定时任务

[Linux]-Crontab定时任务 森格 | 2022年12月 本文是对Linux中的定时任务Crontab的介绍 一、Crontab是什么 crontab命令常见于Unix和类Unix的操作系统之中&#xff0c;用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&…

APP登录界面设计:注册框 or 登录框,哪个更合理?

登录和注册过程往往是产品和用户的 First Sight&#xff0c;因此登录注册入口是给用户留下好的第一印象的关键。遵循“所有的设计都应有据可循”的原则&#xff0c;下面是我司设计团队对“登录界面该放注册框还是登录框这个问题”的探讨。 对于一般需要账号体系的产品&#xff…

Moho Pro - Mac 上一款专业的二维动画制作软件,强大的功能让你尽情发挥创意

Moho Pro - Mac 上一款专业的二维动画制作软件&#xff0c;强大的功能让你尽情发挥创意 Moho&#xff0c;以前被称为动画工作室专业版&#xff0c;是最好的质量的2D动画软件之一。这个程序是理想的专业人士寻找一个更有效的替代方法来创建动画&#xff0c;没有繁琐的详细逐帧处…

[ 漏洞挖掘基础篇六 ] 漏洞挖掘之越权漏洞挖掘

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

用Echarts实现SpreadJS引用从属关系可视化

在金融行业&#xff0c;我们经常会有审计审查的需求&#xff0c;对某个计算结果进行审查&#xff0c;但是这个计算结果可能依赖多个单元格&#xff0c;而且会有会有多级依赖的情况&#xff0c;如果让我们的从业人员靠眼睛找&#xff0c;工作量巨大&#xff0c;而且准确性存疑&a…

图书管理系统【Servlet+HTML综合应用】

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

分享从零开始学习网络设备配置--任务2.7 提高网络稳定性(VRRP)

任务描述 某公司在北京的总部网络承担了连接全国各地分公司网络的任务。总部网络中心采用多台万兆交换机&#xff0c;内部网络按照业务规划有2个部门VLAN。为了增强总部核心网络的稳定性&#xff0c;要求在三层网络设备上配置VRRP备份组&#xff0c;实现网关冗余&#xff0c;为…

BYOL论文精读

文章目录概要背景方法1. 概述2. 参数更新3.目标z_ξ的构建和q_θ的预测结果结论个人看法概要 本篇博客介绍了Bootstrap Your Own Latent (BYOL)方法&#xff0c;这是DeepMind和Imperial London提出的一种自监督学习方法。 BYOL 包含两个架构相同但参数不同的网络。BYOL 不需要…

SpringBoot 项目打成 .exe 程序

准备 准备工作&#xff1a; 1.一个jar包&#xff0c;没有bug能正常启动的jar包 2.exe4j&#xff0c;一个将jar转换成exe的工具 3.inno setup&#xff0c;一个将依赖和exe一起打成一个安装程序的工具 开始 以我为例子&#xff0c;我将jar包放在了桌面 打开安装好的exe4j 直…

面渣逆袭:Java并发六十问,快来看看你会多少道

这篇文章有点长&#xff0c;四万字&#xff0c;图文详解六十道Java并发面试题。人已经肝麻了&#xff0c;大家可以点赞、收藏慢慢看&#xff01;扶我起来&#xff0c;我还能肝&#xff01; 基础 1.并行跟并发有什么区别&#xff1f; 从操作系统的角度来看&#xff0c;线程是…

现在有哪些好用的企业报表软件?

简单来讲&#xff0c;企业报表就是“用表格、图表等格式来动态显示数据”&#xff0c;各行各业、每年每月&#xff0c;都需要通过报表来展示组织和人员在经营管理上的真实情况。当前大家常用的实现企业报表的方式包含代码开发、用 Excel 制作离线报表、开源产品、利用业务系统&…

基于遗传编程的符号回归

0 前言 作为一种监督学习方法&#xff0c;符号回归&#xff08;symbolic regression&#xff09;试图发现某种隐藏的数学公式&#xff0c;以此利用特征变量预测目标变量。 符号回归的具体实现方式是遗传算法&#xff08;genetic algorithm&#xff09;。一开始&#xff0c;一…

数字三角形问题

数字三角形问题一、题目描述二、题目分析1、问题分析2、思路分析&#xff08;1&#xff09;状态转移方程状态表示状态转移&#xff08;2&#xff09;循环的设计三、代码实现一、题目描述 二、题目分析 1、问题分析 这道题给我们的第一眼感觉就是情况太多了&#xff0c;太复杂…

虚拟化环境下,如何高效开展勒索病毒防护加固?

本文重点 近些年&#xff0c;勒索病毒攻击事件频发&#xff0c;由于其“难发现、难阻止、难破解”的特点&#xff0c;不少用户——尤其是使用虚拟化的金融、医疗、制造、公共服务等重要行业用户——已遭受严重数据与经济损失。勒索攻击的防控是一项系统性工程&#xff0c;除了…

2-2-3-9-1-1、jdk1.7HashMap详解

目录数据结构链表的作用链表问题数据结构简图源码解析重要成员变量说明构造函数put操作初始化数组Key为null的处理计算hash添加链表节点--新增Entry扩容缺点扩容死锁分析单线程扩容多线程扩容数据结构 jdk1.7的hashmap的底层结构是数组加单向链表实现的。将key的hash值进行取模…

深度学习环境搭建

深度学习环境搭建0.引言1.Jupyter Notebook1.1.ANACONDA安装1.2.基于conda安装Jupyter Notebook1.3.Jupyter Notebook使用2.Pycharm2.1.安装Pycharm2.2.Pycharm设置0.引言 一步步采坑更新。 1.Jupyter Notebook 官方文档 安装参考 通过安装Anaconda来解决Jupyter Notebook…

300行HTML+CSS+JS代码实现动态圣诞树

文章目录1. 前言2. 效果展示3. 准备&#x1f351; 下载编译器&#x1f351; 下载插件4. 源码&#x1f351; HTML&#x1f351; JS&#x1f351; CSS5. 结语1. 前言 一年一度的圣诞节和考研即将来临&#xff0c;那么这篇文章将用到前端三大剑客 HTML CSS JS 来实现动态圣诞树…