f429 discovery开发版 LVGL移植(带操作系统)

您所在的位置:网站首页 野火f429挑战者 f429 discovery开发版 LVGL移植(带操作系统)

f429 discovery开发版 LVGL移植(带操作系统)

2024-03-09 07:26| 来源: 网络整理| 查看: 265

文章标题 准备STM32F429I-DISC1 开发版CUBEMX 工具 移植CUBEMX生成基础代码FREERTOS时钟树生成 LVGL库移植LVGL 驱动 触摸屏显示触摸 导入keil并编译 烧录附件 本文只针对当时的LVGL v7,LVGL迭代过程中变化较大,部分接口有可能做调整。本文仅供参考

准备

之前的f103的开发版移植了LVGL,分辨率240*320屏幕,如果只有Gauge这种界面局部刷新的控件效果还算差强人意,但只要全屏刷新的话帧数只有十几帧,观感较差。使用场景感觉挺受限。 感觉103这种性能还是不太能玩转GUI,之前看touchgfx也挺卡的。 前几天搞到一块f429 discovery开发版,就再次尝试移植了lvgl,效果不错。

STM32F429I-DISC1 开发版

开发版参数 芯片参数 在这里需要注意的参数 使用的是•STM32F429ZIT6 180 MHz LTDC 驱动( LCD-TFT controller) :屏的驱动,只需要指定显存地址,ltdc会自动dma将显存数据传到tft,比并口快,不过个人没测试过速度差异。 DMA2D:简单来说就是,专门为刷显存的设计的特殊的DMA,带有的图层混合,纯色填充,像素格式转换,显示窗口等功能,比较好用。

CUBEMX 工具

下载地址 方便快速配置外设及一些中间件,可直接生成代码。

移植 CUBEMX生成基础代码

需要主要包括以下几个。注意生成的外设配置代码只包含MCU自身的初始化,部分如SDRAM,tft之类的需要另外初始化外设。不过我这里图省事直接用bsp包初始化了显示ic,ltdc,触摸ic,sdram等。就不用这个工具配置了

FREERTOS

例程放一个刷UI的高优先级进程,专门刷UI。任务栈设置成2k byte,其他默认。 在这里插入图片描述

时钟树

180M,如下 在这里插入图片描述

生成

这里我用的是keil,可按自己需求生成不同的ide项目。

LVGL库移植

在生成的项目里新建 你的工程路径\Middlewares\Third_Party\Lvgl文件夹 将下载的LVGL源码 LVGL源码及example放到该文件夹中 将lvgl/lv_conf_template.h配置文件模板拷贝到LVGL源码上一级目录,改名lv_conf.h,将文件里#if 0 改成#if 1,并按屏幕类型修改分辨率及色深,设置LVGL内存堆大小,并使能使能custom tick ,让lvgl使用freertos的心跳tick,其余默认。

#define LV_HOR_RES_MAX (240) #define LV_VER_RES_MAX (320) #define LV_COLOR_DEPTH 16 # define LV_MEM_SIZE (32U * 1024U) #define LV_TICK_CUSTOM 1 #if LV_TICK_CUSTOM == 1 #define LV_TICK_CUSTOM_INCLUDE "FreeRTOS.h" /*Header for the sys time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (xTaskGetTickCount()) /*Expression evaluating to current systime in ms*/ #endif /*LV_TICK_CUSTOM*/

调用lv_init()以初始化库,并在ui进程中周期性调用lv_task_handler()即可LVGL库的使用

LVGL 驱动 触摸屏

在这里插入图片描述 LVGL和硬件层的交互很简单,只是给driver层提供需要刷新的显存buffer及显示窗口而已, 将lvgl\examples\porting里的lv_port_disp_template与lv_port_indev_template c文件和h文件拷贝出来,一个是LVGL显示驱动模板,一个是LVGL触摸驱动模板 里面需要改动的东西,只有两个对应的回调函数,

显示

LVGL显存稍微改大点,默认是屏幕10行像素点刷一轮,我们改成40行,差不多就能保证默认满帧运行了

static lv_disp_buf_t draw_buf_dsc_1; static lv_color_t draw_buf_1[LV_HOR_RES_MAX *40] ; /*A buffer for 10 rows*/ lv_disp_buf_init(&draw_buf_dsc_1, draw_buf_1, NULL, LV_HOR_RES_MAX *40); /*Initialize the display buffer*/

显示回调函数修改,dma2d刷屏

extern DMA2D_HandleTypeDef hdma2d; extern LTDC_HandleTypeDef hltdc; 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*/ int16_t w = (area->x2 - area->x1 + 1); int16_t h = (area->y2 - area->y1 + 1); uint32_t size = w * h; disp_drv_p = disp_drv; hdma2d.Init.Mode = DMA2D_M2M; hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565; hdma2d.Init.OutputOffset = (LV_HOR_RES_MAX-w); hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; hdma2d.LayerCfg[1].InputAlpha = 0xFF; hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565 ; hdma2d.LayerCfg[1].InputOffset = 0; hdma2d.Instance = DMA2D; /*##-4- DMA2D Initialization ###############################################*/ if(HAL_DMA2D_Init(&hdma2d) != HAL_OK) { Error_Handler(); } if(HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK) { /* Initialization Error */ Error_Handler(); } if(HAL_DMA2D_Start(&hdma2d, (uint32_t)color_p, (uint32_t) (hltdc.LayerCfg[0].FBStartAdress) + 2*(LV_HOR_RES_MAX *area->y1 + area->x1), w, h) != HAL_OK) { /* Initialization Error */ Error_Handler(); } HAL_DMA2D_PollForTransfer(&hdma2d,100); lv_disp_flush_ready(disp_drv); } 触摸

触屏驱动,更改的如下图,主要是获取xy坐标及触摸状态,并提供给lvgl

static TS_StateTypeDef TS_State; static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { static lv_coord_t last_x = 0; static lv_coord_t last_y = 0; BSP_TS_GetState(&TS_State); /*Save the pressed coordinates and the state*/ if(touchpad_is_pressed()) { touchpad_get_xy(&last_x, &last_y); data->state = LV_INDEV_STATE_PR; } else { data->state = LV_INDEV_STATE_REL; } /*Set the last pressed coordinates*/ data->point.x = last_x; data->point.y = last_y; /*Return `false` because we are not buffering and no more data to read*/ return false; } /*Return true is the touchpad is pressed*/ static bool touchpad_is_pressed(void) { /*Your code comes here*/ return TS_State.TouchDetected; } /*Get the x and y coordinates if the touchpad is pressed*/ static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y) { /*Your code comes here*/ *x = Calibration_GetX(TS_State.X); *y = Calibration_GetX(TS_State.Y); }

将void lv_port_disp_init(void)及void lv_port_indev_init(void)声明加入到对应头文件中,lvgl初始化块同时调用void lv_port_indev_init(void)及void lv_port_indev_init(void)即可。

void StartUITask(void *argument) { /* USER CODE BEGIN 5 */ lv_init(); lv_port_disp_init(); lv_port_indev_init(); lv_demo_widgets(); /* Infinite loop */ for(;;) { lv_task_handler(); osDelay(1); } /* USER CODE END 5 */ } 导入keil并编译

在这里插入图片描述 图上的路径include进来,keil项目添加对应group,将lvgl源代码、bsp驱动,lvgl_example测试用例添加进来 由于用了bsp包初始化了显示ic,spi和iic,所以stm32f4xx_hal_conf.h需要开启对应的编译开关。

在这里插入图片描述 接下来还有一些头文件没有包含进来 对应的头文件include处理一下可以烧录了。

#include "lvgl.h" #include "lv_examples.h" #include "lv_port_disp.h" #include "lv_port_indev.h" #include "stm32f429i_discovery.h" #include "stm32f429i_discovery_lcd.h" #include "stm32f429i_discovery_ts.h" 烧录

效果如下,lvgl默认LV_DISP_DEF_REFR_PERIOD 30ms刷新一次,满帧33帧,基本全程满帧运行。在这里插入图片描述 至于优化提高刷新率的方法,后面再做详细介绍。

附件

例程



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3