本帖最后由 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);
}
}
|