f429 discovery开发版 LVGL移植(带操作系统) |
您所在的位置:网站首页 › 野火f429挑战者 › f429 discovery开发版 LVGL移植(带操作系统) |
文章标题
准备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显存稍微改大点,默认是屏幕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并编译
效果如下,lvgl默认LV_DISP_DEF_REFR_PERIOD 30ms刷新一次,满帧33帧,基本全程满帧运行。 例程 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |