硬汉嵌入式论坛

 找回密码
 立即注册
查看: 313|回复: 11
收起左侧

[技术讨论] 关于lvgl fsmc使用dma加速后,一直显示历程的初始页面,触摸无效,开启显示帧率后,这个画面页不显示帧率的问题,求解答

[复制链接]

1

主题

5

回帖

8

积分

新手上路

积分
8
发表于 2025-7-18 20:40:51 | 显示全部楼层 |阅读模式
                                         关于lvgl fsmc使用dma加速后,一直显示历程的初始页面,触摸无效,开启显示帧率后,这个画面页不显示帧率的问题,求解答

相关代码如下

dma初始化

void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* Configure DMA request hdma_memtomem_dma2_stream0 on DMA2_Stream0 */
  hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;
  hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;
  hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;
  hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE;
  hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_DISABLE;
  hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
  hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;
  hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_VERY_HIGH;
  hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
  hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
  hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE;
  hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;
  if (HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK)
  {
    Error_Handler();
  }

  /* DMA interrupt init */
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}


dma中断服务函数

void DMA2_Stream0_IRQHandler(void)
{
    LVGL_LCD_FSMC_DMA_pCallback(&hdma_memtomem_dma2_stream0);
  HAL_DMA_IRQHandler(&hdma_memtomem_dma2_stream0);
}


disp_flush

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
        if(disp_flush_enabled) {
        uint16_t height,width;
                width=area->x2-area->x1+1;                         //得到填充的宽度
                height=area->y2-area->y1+1;                        //高度
        lcd_set_window(area->x1,area->y1,width,height);
        lcd_write_ram_prepare();
        
        HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p, (uint32_t)&LCD->LCD_RAM, height*width); //写数据
        }
}


dma中断回调函数

uint32_t xy=0;
void LVGL_LCD_FSMC_DMA_pCallback(DMA_HandleTypeDef *_hdma)
{   
    xy++;   //这里debug,xy加到0x30之后就停了,不知道为什么
        //lv_disp_flush_ready(&disp_drv);
    lv_disp_flush_ready(lv_disp_get_default()->driver);
}


运行会一直卡在图片上的页面,不显示帧率(已开启显示),大学生入门,求哥哥姐姐们解答

卡着的页面

卡着的页面
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-19 17:25:01 | 显示全部楼层
函数HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p, (uint32_t)&LCD->LCD_RAM, height*width); 后面加个等待执行完成。

然后你的这个函数LVGL_LCD_FSMC_DMA_pCallback(&hdma_memtomem_dma2_stream0);应该放到传输完成回调函数里面,否则任何中断标志都执行一次。
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2025-7-19 20:00:54 | 显示全部楼层
eric2013 发表于 2025-7-19 17:25
函数HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p, (uint32_t)&LCD->LCD_RAM, height ...

还是不行,然后我这个LVGL_LCD_FSMC_DMA_pCallback(&hdma_memtomem_dma2_stream0);函数就是通过HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_CPLT_CB_ID, LVGL_LCD_FSMC_DMA_pCallback);注册的回调函数
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-20 09:24:05 | 显示全部楼层
学习着 发表于 2025-7-19 20:00
还是不行,然后我这个LVGL_LCD_FSMC_DMA_pCallback(&hdma_memtomem_dma2_stream0);函数就是通过HAL_DMA_R ...

最后一个地方,打印下每次height*width值是多少,这个最大65535
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2025-7-22 23:52:00 | 显示全部楼层
eric2013 发表于 2025-7-20 09:24
最后一个地方,打印下每次height*width值是多少,这个最大65535

我用的是800*480的显示屏,很容易就超过了,但是我没开外部SRAM,开双缓存区会报错,内部SRAM不够用,看到分段传输的做法,但毫无头绪
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-23 09:34:57 | 显示全部楼层
学习着 发表于 2025-7-22 23:52
我用的是800*480的显示屏,很容易就超过了,但是我没开外部SRAM,开双缓存区会报错,内部SRAM不够用,看 ...

改成每个width执行一次DMA即可。
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2025-7-23 17:18:35 | 显示全部楼层
本帖最后由 学习着 于 2025-7-23 23:34 编辑
eric2013 发表于 2025-7-23 09:34
改成每个width执行一次DMA即可。

我分段传输后发现还是不行,debug查看了height*width的值,发现根本没超过65535,之前我一直以为800*480的像素很容易超过,我看了下从刷新完第一个页面到卡住,height*width一直是1F40,也才8000,但是到这里后dma就启动不了了

下面是我修改后的函数

        uint16_t height,width;
                width=area->x2-area->x1+1;                         //得到填充的宽度
                height=area->y2-area->y1+1;                        //高度
        lcd_set_window(area->x1,area->y1,width,height);
        lcd_write_ram_prepare();
        uint32_t restPoint = width * height, alreadyPoint = 0;
        do {
        uint32_t pointToShow = restPoint >= 65535 ? 65535 : restPoint;

        
        while (HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)(color_p + alreadyPoint),
                      (uint32_t)&LCD->LCD_RAM, pointToShow)==HAL_OK);

        restPoint -= pointToShow;
        alreadyPoint += pointToShow;
    } while (restPoint);

}


void LVGL_LCD_FSMC_DMA_pCallback(DMA_HandleTypeDef *_hdma)
{
    lv_disp_flush_ready(lv_disp_get_default()->driver);
}



回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-24 08:36:27 | 显示全部楼层
学习着 发表于 2025-7-23 17:18
我分段传输后发现还是不行,debug查看了height*width的值,发现根本没超过65535,之前我一直以为800*480 ...

实现不对,不能这样等待,这个函数(HAL_DMA_Start_IT是非阻塞的,会立即返回

while (HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)(color_p + alreadyPoint),
                      (uint32_t)&LCD->LCD_RAM, pointToShow)==HAL_OK);
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2025-7-24 14:23:16 | 显示全部楼层
eric2013 发表于 2025-7-24 08:36
实现不对,不能这样等待,这个函数(HAL_DMA_Start_IT是非阻塞的,会立即返回

while (HAL_DMA_Start_I ...

       我使用这个写法,发现还是会卡在第一个页面,应该不是传输超过65535的原因 ,同样的dma配置还有写法在320*240的屏幕上就可以正常运行
uint16_t height,width;
                width=area->x2-area->x1+1;                         //得到填充的宽度
                height=area->y2-area->y1+1;                        //高度
        lcd_set_window(area->x1,area->y1,width,height);
        lcd_write_ram_prepare();
        uint32_t restPoint = width * height;
        if(restPoint>=65535)
        {
            alreadyPoint=1;
            lv_disp_flush_ready(lv_disp_get_default()->driver);
        }
        else
        {
            alreadyPoint=0;
            HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p,
                      (uint32_t)&LCD->LCD_RAM, restPoint);
        }


void LVGL_LCD_FSMC_DMA_pCallback(DMA_HandleTypeDef *_hdma)
{
    if(_hdma==&hdma_memtomem_dma2_stream0&&alreadyPoint==0)
    {   
        
        lv_disp_flush_ready(lv_disp_get_default()->driver);
        
    }
}
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-25 10:44:08 | 显示全部楼层
学习着 发表于 2025-7-24 14:23
我使用这个写法,发现还是会卡在第一个页面,应该不是传输超过65535的原因 ,同样的dma配置还有写 ...

函数   HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p,
                      (uint32_t)&LCD->LCD_RAM, restPoint);

后面加个等待DMA操作完成,必加
回复

使用道具 举报

1

主题

5

回帖

8

积分

新手上路

积分
8
 楼主| 发表于 2025-7-25 16:35:03 | 显示全部楼层
eric2013 发表于 2025-7-25 10:44
函数   HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p,
                      (ui ...

HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p,
                      (uint32_t)&LCD->LCD_RAM, restPoint);
这个要怎么等待传输完成呢,这个是立即返回的,不知道怎么等待
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-26 09:17:20 | 显示全部楼层
学习着 发表于 2025-7-25 16:35
HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)color_p,
                      (uint32_t ...

传输完成回调做个标志,等待标志即可
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-11 20:56 , Processed in 0.048927 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表