一、硬件介绍
1、产品特点
STM32H747I-DISCO开发板基于Arm的STM32H747XIH6微控制器拥有Cortex-M7内核(带双精度浮点单元,运行频率高达 480 MHz) 和 Cortex-M4内核(带单精度浮点单元,运行频率高达 240 MHz)的双核性能,板载配备2MB的Flash存储器和1MB的RAM、4英寸TFT LCD触摸显示屏(480x800) 具有MIPI DSI接口等;

规格参数

24 MHz 晶振(X1),用于USB OTG HS PHY 和摄像头模块;
25 MHz 晶振(X2),用于主时钟发生器和以太网 PHY;
32.768 kHz 晶体(X3),用于RTC;
25 MHz 晶振(X4),仅用于STLINK-V3E;
硬件框图

2、功能引脚示意图 / 原理图
主要原理图


二、功能配置
1、LCD屏幕
硬件介绍
4 英寸 TFT-LCD 的分辨率为 480x800 像素,可显示高达 16.7M 种颜色,LCD 与微控制器之间的接口是一个 2-Lane MIPI 信号,带 MIPI DSI 接口;


特性
4 英寸 TFT 彩色 LCD
480(RGB)x800 像素
16.7M 色彩显示
最多两路 MIPI/DSI 数据
电容触摸屏支持单点触摸和手势,或双点触摸
LCD 和触摸屏共用 2.8V-3.3V 电源,背光使用 5V 电源
原理图

2、创建工程
1、工程配置
打开 STM32CubeMX ,选择创建 STM32H747I-DISCO 模板,进行相关配置;




配置LCD接口
屏幕驱动IC:NT35510;
根据驱动IC手册进行相关配置;


配置 Conmmd 命令模式


三、代码编写
1、在工程目录下,创建 BSP文件夹 ,导入屏幕驱动IC等相关文件;
2、将图像转换(ARGB888)后存储在文件中 xxx.h ,用于后续的展示;
效果:在LCD屏幕上显示自定义的图片内容;
主要相关代码
#include "main.h"
#include "cat.h"
#include <stdio.h>
const LCD_UTILS_Drv_t LCD_UTIL_Driver =
{
BSP_LCD_DrawBitmap,
BSP_LCD_FillRGBRect,
BSP_LCD_DrawHLine,
BSP_LCD_DrawVLine,
BSP_LCD_FillRect,
BSP_LCD_ReadPixel,
BSP_LCD_WritePixel,
LCD_GetXSize,
LCD_GetYSize,
BSP_LCD_SetActiveLayer,
BSP_LCD_GetPixelFormat
};
static const uint32_t *Images[] =
{
image_800x480
};
uint8_t pColFull[] = {0x00, 0x00, 0x03, 0x1F}; /* 0 -> 799 */
uint8_t pPage[] = {0x00, 0x00, 0x01, 0xDF}; /* 0 -> 479 */
// 清除缓存
static void LCD_FlushCacheRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
int main(void)
{
MPU_Config();
CPU_CACHE_Enable();
HAL_Init();
SystemClock_Config();
BSP_SDRAM_Init(0);
if (LCD_Init() != BSP_ERROR_NONE)
{
Error_Handler();
}
memset((void *)LCD_FRAME_BUFFER, 0x00, 800U * 480U * 4U); // ARGB8888 全黑
LCD_FlushCacheRect(0, 0, 800, 480);
HAL_DSI_Refresh(&hlcd_dsi);
/* 层0定义为 800x480 的 ARGB8888 帧缓冲 */
Lcd_Ctx[0].ActiveLayer = 0;
Lcd_Ctx[0].PixelFormat = LCD_PIXEL_FORMAT_ARGB8888;
Lcd_Ctx[0].BppFactor = 4;
Lcd_Ctx[0].XSize = 800;
Lcd_Ctx[0].YSize = 480;
__HAL_DSI_WRAPPER_DISABLE(&hlcd_dsi);
LCD_LayertInit(0, LCD_FRAME_BUFFER);
UTIL_LCD_SetFuncDriver(&LCD_UTIL_Driver);
HAL_LTDC_SetPitch(&hlcd_ltdc, Lcd_Ctx[0].XSize, 0);
__HAL_DSI_WRAPPER_ENABLE(&hlcd_dsi);
HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, NT35510_CMD_CASET, pColFull);
HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, NT35510_CMD_RASET, pPage);
/* 拷贝全屏图片 */
CopyPicture((uint32_t *)Images[0], (uint32_t *)LCD_FRAME_BUFFER, 0, 0, 800, 480);
LCD_FlushCacheRect(0, 0, 800, 480);
HAL_DSI_Refresh(&hlcd_dsi);
while (1)
{
HAL_Delay(1000);
}
}
//清除缓存内容
static void LCD_FlushCacheRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
uint32_t bytes_per_pixel = 4; // ARGB8888
uint32_t line_stride = 800 * bytes_per_pixel;
uint32_t addr = (uint32_t)LCD_FRAME_BUFFER + (uint32_t)y * line_stride + (uint32_t)x * bytes_per_pixel;
uint32_t size = (uint32_t)h * line_stride; // 按整行区域清理更安全
// 32字节对齐到 cache line
uint32_t start = addr & ~((uint32_t)0x1F);
uint32_t end = (addr + size + 31U) & ~((uint32_t)0x1F);
SCB_CleanDCache_by_Addr((uint32_t *)start, end - start);
}
int32_t LCD_GetXSize(uint32_t Instance, uint32_t *XSize)
{
*XSize = Lcd_Ctx[0].XSize;
return BSP_ERROR_NONE;
}
int32_t LCD_GetYSize(uint32_t Instance, uint32_t *YSize)
{
*YSize = Lcd_Ctx[0].YSize;
return BSP_ERROR_NONE;
}
static uint8_t LCD_Init(void)
{
DSI_PHY_TimerTypeDef PhyTimings;
NT35510_IO_t IOCtx;
static NT35510_Object_t NT35510Obj;
static void *Lcd_CompObj = NULL;
BSP_LCD_Reset(0);
LCD_MspInit();
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLL3.PLL3M = 5;
PeriphClkInitStruct.PLL3.PLL3N = 160;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
PeriphClkInitStruct.PLL3.PLL3P = 2;
PeriphClkInitStruct.PLL3.PLL3Q = 2;
PeriphClkInitStruct.PLL3.PLL3R = 19;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
hlcd_dsi.Instance = DSI;
HAL_DSI_DeInit(&(hlcd_dsi));
dsiPllInit.PLLNDIV = 100;
dsiPllInit.PLLIDF = DSI_PLL_IN_DIV5;
dsiPllInit.PLLODF = DSI_PLL_OUT_DIV1;
hlcd_dsi.Init.NumberOfLanes = DSI_TWO_DATA_LANES;
hlcd_dsi.Init.TXEscapeCkdiv = 0x4;
HAL_DSI_Init(&(hlcd_dsi), &(dsiPllInit));
CmdCfg.VirtualChannelID = 0;
CmdCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
CmdCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
CmdCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
CmdCfg.ColorCoding = DSI_RGB888;
CmdCfg.CommandSize = HACT;
CmdCfg.TearingEffectSource = DSI_TE_DSILINK;
CmdCfg.TearingEffectPolarity = DSI_TE_RISING_EDGE;
CmdCfg.VSyncPol = DSI_VSYNC_FALLING;
CmdCfg.AutomaticRefresh = DSI_AR_DISABLE;
CmdCfg.TEAcknowledgeRequest = DSI_TE_ACKNOWLEDGE_ENABLE;
HAL_DSI_ConfigAdaptedCommandMode(&hlcd_dsi, &CmdCfg);
LPCmd.LPGenShortWriteNoP = DSI_LP_GSW0P_ENABLE;
LPCmd.LPGenShortWriteOneP = DSI_LP_GSW1P_ENABLE;
LPCmd.LPGenShortWriteTwoP = DSI_LP_GSW2P_ENABLE;
LPCmd.LPGenShortReadNoP = DSI_LP_GSR0P_ENABLE;
LPCmd.LPGenShortReadOneP = DSI_LP_GSR1P_ENABLE;
LPCmd.LPGenShortReadTwoP = DSI_LP_GSR2P_ENABLE;
LPCmd.LPGenLongWrite = DSI_LP_GLW_ENABLE;
LPCmd.LPDcsShortWriteNoP = DSI_LP_DSW0P_ENABLE;
LPCmd.LPDcsShortWriteOneP = DSI_LP_DSW1P_ENABLE;
LPCmd.LPDcsShortReadNoP = DSI_LP_DSR0P_ENABLE;
LPCmd.LPDcsLongWrite = DSI_LP_DLW_ENABLE;
HAL_DSI_ConfigCommand(&hlcd_dsi, &LPCmd);
LTDC_Init();
HAL_DSI_Start(&(hlcd_dsi));
PhyTimings.ClockLaneHS2LPTime = 35;
PhyTimings.ClockLaneLP2HSTime = 35;
PhyTimings.DataLaneHS2LPTime = 35;
PhyTimings.DataLaneLP2HSTime = 35;
PhyTimings.DataLaneMaxReadTime = 0;
PhyTimings.StopWaitTime = 10;
HAL_DSI_ConfigPhyTimer(&hlcd_dsi, &PhyTimings);
IOCtx.Address = 0;
IOCtx.GetTick = BSP_GetTick;
IOCtx.WriteReg = DSI_IO_Write;
IOCtx.ReadReg = DSI_IO_Read;
NT35510_RegisterBusIO(&NT35510Obj, &IOCtx);
Lcd_CompObj = (&NT35510Obj);
NT35510_Init(Lcd_CompObj, NT35510_COLMOD_RGB888, LCD_ORIENTATION_LANDSCAPE);
LPCmd.LPGenShortWriteNoP = DSI_LP_GSW0P_DISABLE;
LPCmd.LPGenShortWriteOneP = DSI_LP_GSW1P_DISABLE;
LPCmd.LPGenShortWriteTwoP = DSI_LP_GSW2P_DISABLE;
LPCmd.LPGenShortReadNoP = DSI_LP_GSR0P_DISABLE;
LPCmd.LPGenShortReadOneP = DSI_LP_GSR1P_DISABLE;
LPCmd.LPGenShortReadTwoP = DSI_LP_GSR2P_DISABLE;
LPCmd.LPGenLongWrite = DSI_LP_GLW_DISABLE;
LPCmd.LPDcsShortWriteNoP = DSI_LP_DSW0P_DISABLE;
LPCmd.LPDcsShortWriteOneP = DSI_LP_DSW1P_DISABLE;
LPCmd.LPDcsShortReadNoP = DSI_LP_DSR0P_DISABLE;
LPCmd.LPDcsLongWrite = DSI_LP_DLW_DISABLE;
HAL_DSI_ConfigCommand(&hlcd_dsi, &LPCmd);
HAL_DSI_ConfigFlowControl(&hlcd_dsi, DSI_FLOW_CONTROL_BTA);
HAL_DSI_ForceRXLowPower(&hlcd_dsi, ENABLE);
return BSP_ERROR_NONE;
}
void LTDC_Init(void)
{
hlcd_ltdc.Instance = LTDC;
HAL_LTDC_DeInit(&hlcd_ltdc);
hlcd_ltdc.Init.HorizontalSync = HSYNC;
hlcd_ltdc.Init.VerticalSync = VSYNC;
hlcd_ltdc.Init.AccumulatedHBP = HSYNC + HBP;
hlcd_ltdc.Init.AccumulatedVBP = VSYNC + VBP;
hlcd_ltdc.Init.AccumulatedActiveH = VSYNC + VBP + VACT;
hlcd_ltdc.Init.AccumulatedActiveW = HSYNC + HBP + HACT;
hlcd_ltdc.Init.TotalHeigh = VSYNC + VBP + VACT + VFP;
hlcd_ltdc.Init.TotalWidth = HSYNC + HBP + HACT + HFP;
hlcd_ltdc.Init.Backcolor.Blue = 0;
hlcd_ltdc.Init.Backcolor.Green = 0;
hlcd_ltdc.Init.Backcolor.Red = 0;
hlcd_ltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hlcd_ltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hlcd_ltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hlcd_ltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hlcd_ltdc.Instance = LTDC;
HAL_LTDC_Init(&hlcd_ltdc);
}
void LCD_LayertInit(uint16_t LayerIndex, uint32_t Address)
{
LTDC_LayerCfgTypeDef layercfg;
layercfg.WindowX0 = 0;
layercfg.WindowX1 = Lcd_Ctx[0].XSize;
layercfg.WindowY0 = 0;
layercfg.WindowY1 = Lcd_Ctx[0].YSize;
layercfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
layercfg.FBStartAdress = Address;
layercfg.Alpha = 255;
layercfg.Alpha0 = 0;
layercfg.Backcolor.Blue = 0;
layercfg.Backcolor.Green = 0;
layercfg.Backcolor.Red = 0;
layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
layercfg.ImageWidth = Lcd_Ctx[0].XSize;
layercfg.ImageHeight = Lcd_Ctx[0].YSize;
HAL_LTDC_ConfigLayer(&hlcd_ltdc, &layercfg, LayerIndex);
}
static int32_t DSI_IO_Write(uint16_t ChannelNbr, uint16_t Reg, uint8_t *pData, uint16_t Size)
{
int32_t ret = BSP_ERROR_NONE;
if (Size <= 1U)
{
if (HAL_DSI_ShortWrite(&hlcd_dsi, ChannelNbr, DSI_DCS_SHORT_PKT_WRITE_P1, Reg, (uint32_t)pData[Size]) != HAL_OK)
{
ret = BSP_ERROR_BUS_FAILURE;
}
}
else
{
if (HAL_DSI_LongWrite(&hlcd_dsi, ChannelNbr, DSI_DCS_LONG_PKT_WRITE, Size, (uint32_t)Reg, pData) != HAL_OK)
{
ret = BSP_ERROR_BUS_FAILURE;
}
}
return ret;
}
static int32_t DSI_IO_Read(uint16_t ChannelNbr, uint16_t Reg, uint8_t *pData, uint16_t Size)
{
int32_t ret = BSP_ERROR_NONE;
if (HAL_DSI_Read(&hlcd_dsi, ChannelNbr, pData, Size, DSI_DCS_SHORT_PKT_READ, Reg, pData) != HAL_OK)
{
ret = BSP_ERROR_BUS_FAILURE;
}
return ret;
}
//DMA2D 整块图像拷贝
static void CopyPicture(uint32_t *pSrc, uint32_t *pDst, uint16_t x, uint16_t y, uint16_t xsize, uint16_t ysize)
{
uint32_t destination = (uint32_t)pDst + (y * 800 + x) * 4;
uint32_t source = (uint32_t)pSrc;
hdma2d.Init.Mode = DMA2D_M2M;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
hdma2d.Init.OutputOffset = 800 - xsize;
hdma2d.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;
hdma2d.Init.RedBlueSwap = DMA2D_RB_REGULAR;
hdma2d.XferCpltCallback = NULL;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0xFF;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
hdma2d.LayerCfg[1].InputOffset = 0;
hdma2d.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR;
hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;
hdma2d.Instance = DMA2D;
/* DMA2D 初始化 */
if (HAL_DMA2D_Init(&hdma2d) == HAL_OK)
{
if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK)
{
if (HAL_DMA2D_Start(&hdma2d, source, destination, xsize, ysize) == HAL_OK)
{
HAL_DMA2D_PollForTransfer(&hdma2d, 100);
}
}
}
}图片转换成ARGB888格式;
#ifndef CAT_H
#define CAT_H
#define CAT_WIDTH 800
#define CAT_HEIGHT 480
#define CAT_PIXEL_COUNT (CAT_WIDTH * CAT_HEIGHT)
// value: AARRGGBB
static const uint32_t image_800x480[CAT_PIXEL_COUNT] = {
0xFF413C30, 0xFF342E21, 0xFF332F22, 0xFF322D20, 0xFF312D20, 0xFF312C20, 0xFF312D20, 0xFF312D1F,
0xFF312C1F, 0xFF312C1F, 0xFF302B1D, 0xFF302B1D, 0xFF312B1E, 0xFF302A1E, 0xFF302B1E, 0xFF312C1E,
.....
.....
};四、程序烧录
1、连接USB数据线至开发板的STLINK-V3E接口;
2、分别选择 CM4 / CM7 程序,点击 Download 分别烧录程序到开发板上;
五、效果演示
LCD屏幕和原图展示的色彩效果对比;
原图


实际效果


我要赚赏金
