我看了很多DMA2D教程都是用阻塞方式来刷新屏, 这样就消耗了性能 相当于没用DMA, 所以我使用DMA2D中断来传输数据

测试平台

stm32f429 + 正点原子7寸1024x600液晶屏 45MHZ刷新率 + LVGL

公有条件:

LTDC刷新率45MHZ, 开启SDRAM 突发传输, LVGL 2个全尺寸缓冲区

 

1 LVGL不使用DMA2D, 使用寄存器DMA2D传输

LVGL配置
#define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the
disp. drv- */ #define LV_USE_GPU_STM32_DMA2D 0 /*If enabling
LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include
path of CMSIS header of target processor e.g. "stm32f769xx.h" or
"stm32f429xx.h" */ #define LV_GPU_DMA2D_CMSIS_INCLUDE "stm32f429xx.h"
LVGL port配置
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*/
//LTDC_Color_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)(color_p));
uint32_t h = area->y2 - area->y1; uint32_t w = area->x2 - area->x1; uint32_t
OffLineSrc = 1024 - (area->x2 - area->x1 +1); uint32_t addr =
LCD_FRAME_BUF_ADDR + 2*(1024*area->y1 + area->x1); // --- 阻塞传输--- // 模式
DMA2D->CR = 0x00000000UL | (1 << 9); // 源地址 DMA2D->FGMAR =
(uint32_t)(uint16_t*)(color_p); // 目标地址 DMA2D->OMAR = (uint32_t)addr; // 输入偏移
DMA2D->FGOR = 0; // 输出偏移 DMA2D->OOR = OffLineSrc; /* 前景层和输出区域都采用的RGB565颜色格式 */
DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_RGB565; DMA2D->OPFCCR =
LTDC_PIXEL_FORMAT_RGB565; DMA2D->NLR = (area->y2-area->y1+1) | ((area->x2
-area->x1 +1) << 16); /* 启动传输 */ DMA2D->CR |= DMA2D_CR_START; /* 等待DMA2D传输完成 */
while (DMA2D->CR & DMA2D_CR_START) {} lv_disp_flush_ready(disp_drv); }
跑benckmark大概是11fps

2  LVGL使用DMA2D, 使用寄存器DMA2D传输
#define LV_USE_GPU 0 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the
disp. drv- */ #define LV_USE_GPU_STM32_DMA2D 1 /*If enabling
LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include
path of CMSIS header of target processor e.g. "stm32f769xx.h" or
"stm32f429xx.h" */ #define LV_GPU_DMA2D_CMSIS_INCLUDE "stm32f429xx.h"
加入宏定义STM32F4

3  LVGL不使用DMA2D, 使用寄存器DMA2D中断传输

 因为如果LVGL开启DMA2D之后, 会进入到DMA2D中断,所以要判断是LVGL内部中断,还是自己的刷图中断, 用volatile uint8_t
g_gpu_state = 0; 这个来判断
#define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the
disp. drv- */ #define LV_USE_GPU_STM32_DMA2D 0 /*If enabling
LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include
path of CMSIS header of target processor e.g. "stm32f769xx.h" or
"stm32f429xx.h" */ #define LV_GPU_DMA2D_CMSIS_INCLUDE "stm32f429xx.h" volatile
uint8_t g_gpu_state = 0; // DMA2D传输完成回调 static void
mDMA2Dcallvack(DMA2D_HandleTypeDef *hdma2d) { if(g_gpu_state==1){ g_gpu_state =
0; lv_disp_flush_ready(&g_disp_drv); } } // dma2D采用HAL初始化 static void
dma2d_use_hal_init(void) { hdma2d.Instance = DMA2D; hdma2d.XferCpltCallback =
mDMA2Dcallvack; if (HAL_DMA2D_Init(&hdma2d) != HAL_OK) { } } /* Initialize your
display and the required peripherals. */ static void disp_init(void) {
dma2d_use_reg_init(); } 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*/
//LTDC_Color_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)(color_p));
uint32_t h = area->y2 - area->y1; uint32_t w = area->x2 - area->x1; uint32_t
OffLineSrc = 1024 - (area->x2 - area->x1 +1); uint32_t addr =
LCD_FRAME_BUF_ADDR + 2*(1024*area->y1 + area->x1); // -- 中断传输 // 模式 DMA2D->CR =
0x00000000UL | (1 << 9); // 源地址 DMA2D->FGMAR = (uint32_t)(uint16_t*)(color_p);
// 目标地址 DMA2D->OMAR = (uint32_t)addr; // 输入偏移 DMA2D->FGOR = 0; // 输出偏移
DMA2D->OOR = OffLineSrc; /* 前景层和输出区域都采用的RGB565颜色格式 */ DMA2D->FGPFCCR =
DMA2D_OUTPUT_RGB565; DMA2D->OPFCCR = DMA2D_OUTPUT_RGB565; // 多少行 DMA2D->NLR =
(area->y2-area->y1+1) | ((area->x2 -area->x1 +1) << 16); // 开启中断 DMA2D->CR |=
DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE; /* 启动传输 */ DMA2D->CR |= DMA2D_CR_START;
g_gpu_state = 1; }
4 3  LVGL使用DMA2D, 使用寄存器DMA2D中断传输
#define LV_USE_GPU 0 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the
disp. drv- */ #define LV_USE_GPU_STM32_DMA2D 1 /*If enabling
LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include
path of CMSIS header of target processor e.g. "stm32f769xx.h" or
"stm32f429xx.h" */ #define LV_GPU_DMA2D_CMSIS_INCLUDE "stm32f429xx.h" volatile
uint8_t g_gpu_state = 0; // DMA2D传输完成回调 static void
mDMA2Dcallvack(DMA2D_HandleTypeDef *hdma2d) { if(g_gpu_state==1){ g_gpu_state =
0; lv_disp_flush_ready(&g_disp_drv); } } // dma2D采用HAL初始化 static void
dma2d_use_hal_init(void) { hdma2d.Instance = DMA2D; hdma2d.XferCpltCallback =
mDMA2Dcallvack; if (HAL_DMA2D_Init(&hdma2d) != HAL_OK) { } } /* Initialize your
display and the required peripherals. */ static void disp_init(void) {
dma2d_use_reg_init(); } 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*/
//LTDC_Color_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)(color_p));
uint32_t h = area->y2 - area->y1; uint32_t w = area->x2 - area->x1; uint32_t
OffLineSrc = 1024 - (area->x2 - area->x1 +1); uint32_t addr =
LCD_FRAME_BUF_ADDR + 2*(1024*area->y1 + area->x1); // -- 中断传输 // 模式 DMA2D->CR =
0x00000000UL | (1 << 9); // 源地址 DMA2D->FGMAR = (uint32_t)(uint16_t*)(color_p);
// 目标地址 DMA2D->OMAR = (uint32_t)addr; // 输入偏移 DMA2D->FGOR = 0; // 输出偏移
DMA2D->OOR = OffLineSrc; /* 前景层和输出区域都采用的RGB565颜色格式 */ DMA2D->FGPFCCR =
DMA2D_OUTPUT_RGB565; DMA2D->OPFCCR = DMA2D_OUTPUT_RGB565; // 多少行 DMA2D->NLR =
(area->y2-area->y1+1) | ((area->x2 -area->x1 +1) << 16); // 开启中断 DMA2D->CR |=
DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE; /* 启动传输 */ DMA2D->CR |= DMA2D_CR_START;
g_gpu_state = 1; }
 

对比:

1 不使用GPU,使用寄存器DMA2D,11fps

2 使用GPU,使用寄存器DMA2D, 23fps

3 不使用GPU,使用寄存器DMA2D中断传输, 11fps 

4 使用GPU,中断传输, 30fps

另外我发现开单缓冲比双缓冲快很多, 这个bug估计未来会优化

因为1和3, fps相等是因为在颜色转换消耗了太多时间, 所以中断和阻塞方式基本上差不

听说打开优化等级和编译器等级会更快, 可以试试这个

 

另外自己写DMA2D中断和采用HAL的回调基本参没什么差距, 所以建议直接采用HAL库的回调
void DMA2D_IRQHandler(void) { if ((DMA2D->ISR & DMA2D_FLAG_TC) != 0U) { if
((DMA2D->CR & DMA2D_IT_TC) != 0U) { DMA2D->CR &= ~DMA2D_IT_TC; DMA2D->IFCR
=DMA2D_FLAG_TC; if(g_gpu_state==1){ g_gpu_state = 0;
lv_disp_flush_ready(&g_disp_drv); } } } }
 

技术
©2019-2020 Toolsou All rights reserved,
Vue.js入门(五)---在vue中使用echarts词云Pandas统计分析基础_数据处理(DataFrame常用操作)element UI dialog点击dialog区域外会关闭dialog应届毕业生看过来!Java面试经典77问,看完离工作就不远了关于蓝桥杯大赛,你应该了解的那些事!mysql 分区-key分区(五)海康威视-嵌入式软件笔试题PHP Redis 监听过期的 key 事件C语言循环语句笔记详解以及练习-折半查找算法、猜数字游戏JVM概述