3288|4

501

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

【微雪RP2040双核开发板】LVGL移植 [复制链接]

RP2040-LCD-1.28.zip (28.11 MB, 下载次数: 24)

准备

基于样例的c工程进行

git clone https://github.com/lvgl/lvgl.git

下载代码到RP2040-LCD-1.28\c\lib目录下

 

移植过程

配置文件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/h到RP2040-LCD-1.28\c

改名字为

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

添加文件

如下

 

RP2040-LCD-1.28/c/CMakeLists.txt中

add_subdirectory(./lib/lvgl)

添加lvgl的源码

 

然后调用RP2040-LCD-1.28/c/lib/lvgl/CMakeLists.txt

最终调用

RP2040-LCD-1.28/c/lib/lvgl/env_support/cmake/custom.cmake

需要移植的代码

移植比较简单,直接使用底层驱动模板根据实际实现修改lv_port_disp.c,并配置lv_conf.h即可。

头文件包含模式

需要在工程中定义宏

#define LV_LVGL_H_INCLUDE_SIMPLE 1

这样需要将lvgl.h所在路径配置为工程头文件包含路径。

代码中直接#include "lvgl.h"即可

否则是#include "../../lvgl.h"

 

lib/lvgl/env_support/cmake/custom.cmake中

该宏默认是使能的

option(LV_LVGL_H_INCLUDE_SIMPLE

       "Use #include \"lvgl.h\" instead of #include \"../../lvgl.h\"" ON)

分辨率配置

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_1in28.h"

disp_flush

/*put_px(x, y, color_p)/改为

lcd_draw_point(x,y,color_p->full);

并调用LcdPush();

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)

{

    if(disp_flush_enabled) {

        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

        volatile int32_t x;

        volatile int32_t y;

        printf("%d %d %d %d\r\n",area->y1,area->y2,area->x1,area->x2);

        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)*/

                lcd_draw_point(x,y,color_p->full);

                color_p++;

            }

        }

        LcdPush();

    }

    /*IMPORTANT!!!

     *Inform the graphics library that you are ready with the flushing*/

    lv_disp_flush_ready(disp_drv);

}

 

lib/LCD/LCD_1in28.c中实现

static uint16_t s_disbuffer_au16[LCD_1IN28_WIDTH][LCD_1IN28_HEIGHT];

void lcd_draw_point(int32_t x,int32_t y,uint16_t color)

{

    s_disbuffer_au16[y][x] = (color>>8) | ((color&0xFF)<<8);

}

void LcdPush(void)

{

    LCD_1IN28_SetWindows(0, 0, LCD_1IN28_WIDTH, LCD_1IN28_HEIGHT);

    DEV_Digital_Write(LCD_DC_PIN, 1);

    spi_write_blocking(SPI_PORT, (uint8_t *)&s_disbuffer_au16[0][0], LCD_1IN28_HEIGHT*LCD_1IN28_WIDTH*2);

    ///UWORD j;

    ///for(j = 0; j < LCD_1IN28_HEIGHT; j++){

    //    DEV_SPI_Write_nByte((uint8_t *)&s_disbuffer_au16[j*LCD_1IN28_WIDTH], LCD_1IN28_WIDTH*2);

    //}

}

 

lib/LCD/LCD_1in28.h中申明

void lcd_draw_point(int32_t x,int32_t y,uint16_t color);

void LcdPush(void);

 

颜色深度

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_CUSTOM为1则需要用户提供相关接口

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更新时间滴答,比如专门在某个定时线程中

bool timer_callback(repeating_timer_t *rt)

{

    lv_tick_inc(5);

}

add_repeating_timer_ms(5,timer_callback,0,0);

 

日志

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

工程配置

RP2040-LCD-1.28\c\CMakeLists.txt中

添加

add_subdirectory(./lib/lvgl)

include_directories(./lib/lvgl)

include_directories(.)

add_definitions(-DLV_LVGL_H_INCLUDE_SIMPLE=1)

add_executable(main

main.c lv_port_disp.c

)

target_link_libraries(main examples lvgl LCD QMI8658 GUI Fonts Config pico_stdlib hardware_spi hardware_i2c )

examples/CMakeLists.txt中

include_directories(../lib/lvgl)

add_definitions(-DLV_LVGL_H_INCLUDE_SIMPLE=1)

 

测试

创建一个按钮

examples/LCD_1in28_test.c

#include "LCD_Test.h"

#include "LCD_1in28.h"

#include "QMI8658.h"

#include <stdio.h>

#include "pico/stdlib.h"

#include "hardware/adc.h"

#include "draw.h"

#include "lvgl.h"

#include "lv_port_disp.h"

bool timer_callback(repeating_timer_t *rt)

{

    lv_tick_inc(5);

    ///printf("%lld\r\n",time_us_64());

}

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);

}

struct repeating_timer timer;

int LCD_1in28_test(void)

{

    if (DEV_Module_Init() != 0)

    {

        return -1;

    }

    adc_init();

    adc_gpio_init(29);

    adc_select_input(3);

    LCD_1IN28_Init(VERTICAL);

    LCD_1IN28_Clear(WHITE);

    DEV_SET_PWM(60);

    add_repeating_timer_ms(5,timer_callback,0,&timer);

    ///sleep_ms(5000);

    lv_init();

    lv_port_disp_init();

    lv_example_get_started_1();

    while(1)

    {

        sleep_us(1000); /* 必须又sleep 否则定时器不会回调 */

        lv_task_handler();  

    }

    DEV_Module_Exit();

    return 0;

}

 

效果如下

 

镜像处理

写点函数交换xy即可

 

颜色处理

16位565模式,高低字节需要交换下

void lcd_draw_point(int32_t x,int32_t y,uint16_t color)

{

    s_disbuffer_au16[y][x] = (color>>8) | ((color&0xFF)<<8);

}

 

编译

cd build

export PICO_SDK_PATH="/home/lhj/pico-setup/pico/pico-sdk" && cmake ..

Make

不编译demo,example

export PICO_SDK_PATH="/home/lhj/pico-setup/pico/pico-sdk" && cmake -DLV_CONF_BUILD_DISABLE_EXAMPLES=1 -DLV_CONF_BUILD_DISABLE_DEMOS=1 ..

 

不要用dor循环书信屏幕,直接调用spi_write_blocking

for循环编译器会优化导致逻辑错误,可能并不会按照循环次数循环,而是卡死。

void LcdPush(void)

{

    LCD_1IN28_SetWindows(0, 0, LCD_1IN28_WIDTH, LCD_1IN28_HEIGHT);

    DEV_Digital_Write(LCD_DC_PIN, 1);

    spi_write_blocking(SPI_PORT, (uint8_t *)&s_disbuffer_au16[0][0], LCD_1IN28_HEIGHT*LCD_1IN28_WIDTH*2);

    ///UWORD j;

    ///for(j = 0; j < LCD_1IN28_HEIGHT; j++){

    //    DEV_SPI_Write_nByte((uint8_t *)&s_disbuffer_au16[j*LCD_1IN28_WIDTH], LCD_1IN28_WIDTH*2);

    //}

}

 

参考

https://lvgl.io/

 

此帖出自移动便携论坛

最新回复

谢谢指导   详情 回复 发表于 2022-12-10 12:12
点赞 关注
 
 

回复
举报

6587

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

基于样例的c工程进行的还是可以借鉴的

分享的 RP2040-LCD-1.28压缩文件为什么这么大呀

此帖出自移动便携论坛
 
 
 

回复

6841

帖子

11

TA的资源

版主

板凳
 
LVGL,可以适配这个圆形的屏吗?
此帖出自移动便携论坛

点评

屏幕是240x240,需要应用层自己去规划只使用圆形的区域, 周边的不用。  详情 回复 发表于 2022-12-9 22:50
 
 
 

回复

501

帖子

4

TA的资源

纯净的硅(高级)

4
 
lugl4313820 发表于 2022-12-9 22:47 LVGL,可以适配这个圆形的屏吗?

屏幕是240x240,需要应用层自己去规划只使用圆形的区域,

周边的不用。

此帖出自移动便携论坛

点评

谢谢指导  详情 回复 发表于 2022-12-10 12:12
 
 
 

回复

6841

帖子

11

TA的资源

版主

5
 
qinyunti 发表于 2022-12-9 22:50 屏幕是240x240,需要应用层自己去规划只使用圆形的区域, 周边的不用。

谢谢指导

此帖出自移动便携论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
推荐帖子
【EEWORLD模块整理】+tlc2543(A/D)

今年我用的模块资料 已经证实好用

FPGA DCM时钟管理单元的理解

看Xilinx的Datasheet会注意到Xilinx的FPGA没有PLL,其实DCM就是时间管理单元。 --------------------------------------------- ...

电烙铁的使用小技巧

本人原创——乃自己当时查阅的资料和自己的一点点经验而写成,如有错误请多指教! 首先要说明的是,使用电烙 ...

ubuntu下修改内核发生“ncurses libraries“错误(解决方法)

BSEC@bsec-server:~/kernel/Kernel$ make menuconfig HOSTCC scripts/basic/fixdep HOSTCC scripts/basic/docproc HOSTCC script ...

在屏幕上显示大写字母DMH的VGA控制器

本帖最后由 PuesueDream 于 2015-7-22 17:18 编辑 基于ise14.7平台,用Nexys3开发板弄了一个显示程序。程序包含六部分 首 ...

msp430f149波特率设置

本帖最后由 灞波儿奔 于 2020-1-10 23:14 编辑 TI MSP430系列单片机,usart模块的波特率值设定是通过以下三个寄存器决定的 ...

为什么给一个变量赋值0时,直接写=0,而给它赋值0xffffffff时要写成=0xffffffffu

为什么给一个变量赋值0时,直接写*ram=0即可,而给它赋值0xffffffff时要写成*ram=0xffffffffu, 以下是具体的代码 /****** ...

报名提醒:最后几小时,100套价值390元平头哥RISC-V生态开发板免费送~

最后几小时啦,想要的网友速速来~100套价值390元平头哥RISC-V生态开发板——RVB2601来袭,现在提交创意,即有机会免费 ...

在现代计算机上运行虚拟Mac Quadra 900

682909 macintosh.js 是一个模拟 1991 年 Macintosh Quadra 900 和摩托罗拉 CPU 的虚拟机,它完全用 JavaScript 编写(因此请 ...

反激电源辅助供电绕组串联电阻

看到很多反激电源辅助绕组串联电阻的,如下图电阻Rvcc,想问一下这个电阻的作用是什么?

关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表