[STM32H7]

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

[复制链接]
1052|1
手机看帖
扫描二维码
随时随地手机跟帖
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。
  /* Initialize the region corresponding to external RAM */
#if defined ( __ICCARM__ )
  extern uint32_t __region_EXTRAM_start__;
  extern uint32_t __region_EXTRAM_end__;

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

#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
  extern uint32_t Image$RW_EXTRAM$Base;
  extern uint32_t Image$RW_EXTRAM$ZI$Length;
  extern uint32_t Image$RW_EXTRAM$Length;

  address = (uint32_t)&Image$RW_EXTRAM$Base;
  size  = (uint32_t)&Image$RW_EXTRAM$Length + (uint32_t)&Image$RW_EXTRAM$ZI$Length;
#elif defined ( __GNUC__ )
  extern uint32_t __EXTRAM_BEGIN;
  extern uint32_t __EXTRAM_SIZE;
  address = (uint32_t)&__EXTRAM_BEGIN;
  size  = (uint32_t)&__EXTRAM_SIZE;
#else
#error "Compiler toolchain is unsupported"
#endif

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

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


3、LTDC初始化:MX_LTDC_Init();

其中配置了一个LAYER:pLayerCfg。
hltdc.Instance = LTDC;
  hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
  hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
  hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
  hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
  hltdc.Init.HorizontalSync = 3;
  hltdc.Init.VerticalSync = 3;
  hltdc.Init.AccumulatedHBP = 11;
  hltdc.Init.AccumulatedVBP = 11;
  hltdc.Init.AccumulatedActiveW = 811;
  hltdc.Init.AccumulatedActiveH = 491;
  hltdc.Init.TotalWidth = 819;
  hltdc.Init.TotalHeigh = 499;
  hltdc.Init.Backcolor.Blue = 0;
  hltdc.Init.Backcolor.Green = 0;
  hltdc.Init.Backcolor.Red = 0;
        
  if (HAL_LTDC_Init(&hltdc) != HAL_OK)
  {
    Error_Handler();
  }
  pLayerCfg.WindowX0 = 0;
  pLayerCfg.WindowX1 = 800;
  pLayerCfg.WindowY0 = 0;
  pLayerCfg.WindowY1 = 480;
  pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
  pLayerCfg.Alpha = 255;
  pLayerCfg.Alpha0 = 0;
  pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
  pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
  pLayerCfg.FBStartAdress = (uint32_t)&g_ltdc_lcd_framebuf;
  pLayerCfg.ImageWidth = LAYER_SIZE_X;
  pLayerCfg.ImageHeight = LAYER_SIZE_Y;
  pLayerCfg.Backcolor.Blue = 0;
  pLayerCfg.Backcolor.Green = 0;
  pLayerCfg.Backcolor.Red = 0;
  if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
  {
    Error_Handler();
  }


为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到目标地址
static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize,
uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex)
{

   hdma2d.Init.Mode         = DMA2D_R2M;
   hdma2d.Init.ColorMode    = DMA2D_OUTPUT_RGB565;
   hdma2d.Init.OutputOffset = OffLine;

   hdma2d.Instance = DMA2D;

   /* DMA2D 初始化 */
   if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) {
      if (HAL_DMA2D_ConfigLayer(&hdma2d, LayerIndex) == HAL_OK) {
            if (HAL_DMA2D_Start(&hdma2d, (uint32_t)ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) {
               /* DMA轮询传输 */
               HAL_DMA2D_PollForTransfer(&hdma2d, 100);
            }
      }
   }
}
2、画矩形
void LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height,uint32_t Color)
{
   uint32_t  x_address = 0;


   /* 设置矩形开始地址 */
if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
   x_address = (hltdc.LayerCfg[0].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
   } else if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) {
      x_address = (hltdc.LayerCfg[0].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
   } else if ((hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
               (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
               (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) {
      x_address = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
   } else {
      x_address = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
   }
   /* 填充矩形 */
        LL_FillBuffer(0, (uint32_t *)x_address, Width, Height, (LCD_GetXSize() - Width), Color);
}
3、画横线
void LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length,uint32_t Color)
{
   uint32_t  Xaddress = 0;

   if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
   } else if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
   } else if ((hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
               (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
               (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
   } else {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + (LCD_GetXSize()*Ypos + Xpos);
   }
   /* 填充数据 */
   LL_FillBuffer(0, (uint32_t *)Xaddress, Length, 1, 0, Color);
}


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

   if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 4*(LCD_GetXSize()*Ypos + Xpos);
   } else if (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 3*(LCD_GetXSize()*Ypos + Xpos);
   } else if ((hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \
               (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \
               (hltdc.LayerCfg[0].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + 2*(LCD_GetXSize()*Ypos + Xpos);
   } else {
      Xaddress = (hltdc.LayerCfg[0].FBStartAdress) + (LCD_GetXSize()*Ypos + Xpos);
   }

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



三、画个直方图


typedef struct{
        uint16_t posX;
        uint16_t posY;
        uint16_t height;
        uint16_t width;
        uint32_t color;
}ZFTU;

ZFTU zftu[6];
static void init_zftu(void)
{
        uint8_t i;
        for(i=0;i<6;i++)
        {
                zftu[i].width=80;
                zftu[i].height=80+i*40;
                zftu[i].posX=120*i+50;
                zftu[i].posY=80;
                zftu[i].color=0x00FF0000>>i*2;
        }
}

static void draw_zftu(void)
{
        uint8_t i;
        for(i=0;i<6;i++)
        {
                LCD_FillRect(zftu[i].posX,480-zftu[i].height-zftu[i].posY,zftu[i].width,zftu[i].height,zftu[i].color);
        }
}
微信图片_20240920193308.jpg

使用特权

评论回复
烟雨蒙蒙520| | 2024-9-29 01:24 | 显示全部楼层
由于DMA2D和LTDC的操作是硬件加速的,尽量避免在主循环中执行阻塞操作

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

36

帖子

0

粉丝