stm32 DMA2D使用中断LVGL,提高LVGL帧率
发布日期:2021-05-09 16:41:13 浏览次数:20 分类:精选文章

本文共 6344 字,大约阅读时间需要 21 分钟。

我看了很多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 processore.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 processore.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 processore.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 processore.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);			 }    }  }}

 

上一篇:esp8266 esp32使用http post往flask发送json数据以及解析json
下一篇:stm32 DMA2D知识点

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年04月21日 08时55分01秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章