[STM32H7] 【STM32H7S78-DK测评】8、LTDC+DMA2D驱动屏幕

[复制链接]
 楼主| sujingliang 发表于 2024-9-20 19:34 | 显示全部楼层 |阅读模式
<
本帖最后由 sujingliang 于 2024-10-1 09:44 编辑

目标
通过LTDC+DMA2D驱动STIM32H7S78-DK自带屏幕。


‌LTDC(LCD-TFT Display Controller)‌是一个用于直接控制外部TFT-LCD屏幕的控制器,它提供了RGB信号和控制信号来驱动LCD显示屏。

‌LTDC可以独立工作,直接驱动屏幕。‌当然如果想工作得更好,需要和DMA2D配合,DMA2D相当于STM32的GPU。二者集成,可以实现图像直接复制到LTDC接口上,实现图像的显示,且完全由硬件实现,不占用CPU资源。

DEMO中有一个LTDC+DMA2D例程位于:
STM32Cube_FW_H7RS_V1.1.0\Projects\STM32H7S78-DK\Examples\DMA2D\DMA2D_RegToMemWithLCD


各种配置都有具有可以直接拿来修改。


一、初始化部分

1、配置RAM:MPU_Config();
为了驱动屏幕MPU是必须的,因为处理屏幕图像,必须要大容量的显存,MCU内部的RAM肯定不够,所以需要MPU驱动外部RAM。
  1.   /* Initialize the region corresponding to external RAM */
  2. #if defined ( __ICCARM__ )
  3.   extern uint32_t __region_EXTRAM_start__;
  4.   extern uint32_t __region_EXTRAM_end__;

  5.   address = (uint32_t)&__region_EXTRAM_start__;
  6.   size = (uint32_t)&__region_EXTRAM_end__ - (uint32_t)&__region_EXTRAM_start__ + 1;

  7. #elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
  8.   extern uint32_t Image$RW_EXTRAM$Base;
  9.   extern uint32_t Image$RW_EXTRAM$ZI$Length;
  10.   extern uint32_t Image$RW_EXTRAM$Length;

  11.   address = (uint32_t)&Image$RW_EXTRAM$Base;
  12.   size  = (uint32_t)&Image$RW_EXTRAM$Length + (uint32_t)&Image$RW_EXTRAM$ZI$Length;
  13. #elif defined ( __GNUC__ )
  14.   extern uint32_t __EXTRAM_BEGIN;
  15.   extern uint32_t __EXTRAM_SIZE;
  16.   address = (uint32_t)&__EXTRAM_BEGIN;
  17.   size  = (uint32_t)&__EXTRAM_SIZE;
  18. #else
  19. #error "Compiler toolchain is unsupported"
  20. #endif

  21.   if (size != 0)
  22.   {
  23.     MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  24.     MPU_InitStruct.Number = index;
  25.     MPU_InitStruct.SubRegionDisable = 0u;
  26.     MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  27.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  28.     MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  29.     MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  30.     MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  31.     MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
  32.     MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
  33.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
  34.     index++;
  35.   }
上面Image$$RW_EXTRAM$$Base;对应散列文件中RW_EXTRAM。
  1.   RW_EXTRAM 0x90000000 0x2000000  {
  2.         .ANY (+RW +ZI)
  3.   }
分散加载文件这里加上.ANY (+RW +ZI),就可以在申请内存的时候自动使用外部RAM了。

2、DMA2D初始化:MX_DMA2D_Init();
DMA2D_R2M:寄存器到存储
  1.   hdma2d.Instance = DMA2D;
  2.   hdma2d.Init.Mode = DMA2D_R2M;
  3.   hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB4444;
  4.   hdma2d.Init.OutputOffset = 0;
  5.   if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
  6.   {
  7.     Error_Handler();
  8.   }


3、LTDC初始化:MX_LTDC_Init();

其中配置了一个LAYER:pLayerCfg。
  1. hltdc.Instance = LTDC;
  2.   hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
  3.   hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
  4.   hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
  5.   hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
  6.   hltdc.Init.HorizontalSync = 3;
  7.   hltdc.Init.VerticalSync = 3;
  8.   hltdc.Init.AccumulatedHBP = 11;
  9.   hltdc.Init.AccumulatedVBP = 11;
  10.   hltdc.Init.AccumulatedActiveW = 811;
  11.   hltdc.Init.AccumulatedActiveH = 491;
  12.   hltdc.Init.TotalWidth = 819;
  13.   hltdc.Init.TotalHeigh = 499;
  14.   hltdc.Init.Backcolor.Blue = 0;
  15.   hltdc.Init.Backcolor.Green = 0;
  16.   hltdc.Init.Backcolor.Red = 0;
  17.         
  18.   if (HAL_LTDC_Init(&hltdc) != HAL_OK)
  19.   {
  20.     Error_Handler();
  21.   }
  22.   pLayerCfg.WindowX0 = 0;
  23.   pLayerCfg.WindowX1 = 800;
  24.   pLayerCfg.WindowY0 = 0;
  25.   pLayerCfg.WindowY1 = 480;
  26.   pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
  27.   pLayerCfg.Alpha = 255;
  28.   pLayerCfg.Alpha0 = 0;
  29.   pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
  30.   pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
  31.   pLayerCfg.FBStartAdress = (uint32_t)&g_ltdc_lcd_framebuf;
  32.   pLayerCfg.ImageWidth = LAYER_SIZE_X;
  33.   pLayerCfg.ImageHeight = LAYER_SIZE_Y;
  34.   pLayerCfg.Backcolor.Blue = 0;
  35.   pLayerCfg.Backcolor.Green = 0;
  36.   pLayerCfg.Backcolor.Red = 0;
  37.   if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
  38.   {
  39.     Error_Handler();
  40.   }


为LTDS设置地址
/* DMA2D output address in SRAM : this is the buffer displayed on LCD screen */
HAL_LTDC_SetAddress(&hltdc, (uint32_t)(&g_ltdc_lcd_framebuf), LTDC_LAYER_1);

其中g_ltdc_lcd_framebuf设置成:
uint16_t g_ltdc_lcd_framebuf[1280][800];
可能设大,这么大的空间也只能放到外部RAM中。

二、添加DMA2D绘图函数
这部分参考野火资料
1、填充COLOR到目标地址
  1. static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize,
  2. uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex)
  3. {

  4.    hdma2d.Init.Mode         = DMA2D_R2M;
  5.    hdma2d.Init.ColorMode    = DMA2D_OUTPUT_RGB565;
  6.    hdma2d.Init.OutputOffset = OffLine;

  7.    hdma2d.Instance = DMA2D;

  8.    /* DMA2D 初始化 */
  9.    if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) {
  10.       if (HAL_DMA2D_ConfigLayer(&hdma2d, LayerIndex) == HAL_OK) {
  11.             if (HAL_DMA2D_Start(&hdma2d, (uint32_t)ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) {
  12.                /* DMA轮询传输 */
  13.                HAL_DMA2D_PollForTransfer(&hdma2d, 100);
  14.             }
  15.       }
  16.    }
  17. }
2、画矩形
  1. void LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height,uint32_t Color)
  2. {
  3.    uint32_t  x_address = 0;


  4.    /* 设置矩形开始地址 */
  5. if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
  6.    x_address = (hltdc.LayerCfg[0].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
  7.    } else if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) {
  8.       x_address = (hltdc.LayerCfg[0].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
  9.    } else if ((hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
  10.                (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
  11.                (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) {
  12.       x_address = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
  13.    } else {
  14.       x_address = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
  15.    }
  16.    /* 填充矩形 */
  17.         LL_FillBuffer(0, (uint32_t *)x_address, Width, Height, (LCD_GetXSize() - Width), Color);
  18. }
3、画横线
  1. void LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length,uint32_t Color)
  2. {
  3.    uint32_t  Xaddress = 0;

  4.    if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
  5.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
  6.    } else if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) {
  7.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
  8.    } else if ((hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
  9.                (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
  10.                (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) {
  11.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
  12.    } else {
  13.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + (LCD_GetXSize()*Ypos + Xpos);
  14.    }
  15.    /* 填充数据 */
  16.    LL_FillBuffer(0, (uint32_t *)Xaddress, Length, 1, 0, Color);
  17. }


4、画竖线
  1. void LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length,uint32_t Color)
  2. {
  3.    uint32_t  Xaddress = 0;

  4.    if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
  5.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
  6.    } else if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) {
  7.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
  8.    } else if ((hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
  9.                (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
  10.                (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) {
  11.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
  12.    } else {
  13.       Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + (LCD_GetXSize()*Ypos + Xpos);
  14.    }

  15.    /* 填充数据 */
  16.    LL_FillBuffer(0, (uint32_t *)Xaddress, 1, Length, (LCD_GetXSize() - 1), Color);
  17. }



三、画个直方图


  1. typedef struct{
  2.         uint16_t posX;
  3.         uint16_t posY;
  4.         uint16_t height;
  5.         uint16_t width;
  6.         uint32_t color;
  7. }ZFTU;

  8. ZFTU zftu[6];
  9. static void init_zftu(void)
  10. {
  11.         uint8_t i;
  12.         for(i=0;i<6;i++)
  13.         {
  14.                 zftu[i].width=80;
  15.                 zftu[i].height=80+i*40;
  16.                 zftu[i].posX=120*i+50;
  17.                 zftu[i].posY=80;
  18.                 zftu[i].color=0x00FF0000>>i*2;
  19.         }
  20. }

  21. static void draw_zftu(void)
  22. {
  23.         uint8_t i;
  24.         for(i=0;i<6;i++)
  25.         {
  26.                 LCD_FillRect(zftu[i].posX,480-zftu[i].height-zftu[i].posY,zftu[i].width,zftu[i].height,zftu[i].color);
  27.         }
  28. }
微信图片_20240920193308.jpg
烟雨蒙蒙520 发表于 2024-9-29 01:24 | 显示全部楼层
由于DMA2D和LTDC的操作是硬件加速的,尽量避免在主循环中执行阻塞操作
Amazingxixixi 发表于 2024-10-31 16:09 | 显示全部楼层
2D驱动自带加速,还是很值得推荐的。
suncat0504 发表于 2024-10-31 17:11 | 显示全部楼层
有2D处理,这单片机的性能越来越强悍了。
地瓜patch 发表于 2024-10-31 18:28 来自手机 | 显示全部楼层
芯片性能高了,显示效果真炫
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

146

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部