MIPI-DSI LTDC configuration lcd
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2025-05-08 9:35 AM
Hello everyone, I need help with a DSI + LTDC configuration.
I'm working on a custom board with an STM32H747BIT and trying to drive a 720x1280 RGB888 display without GRAM, using the ILI9881C controller via DSIHOST + LTDC.
Here’s the situation:
I’m currently testing at 500 Mbps per DSI lane (i.e., 62.5 MHz per lane, 2 lanes total) and 50 MHz LTDC pixel clock.
The built-in test pattern works fine, but when I try to draw using the framebuffer, the image is misaligned, sometimes flickers, and the drawing coordinates are not correct.
For example, when I try to draw two horizontal bands, the first one appears larger than expected.
I suspect it’s related to timing parameters like HSA, HBP, HFP, VSA, VBP, VFP – but the datasheet for the display doesn't provide them.
Observations and questions:
To get the correct colors, I had to set ARGB8888 in LTDC, even though the display is RGB888.
Without the missing timing values, I can’t estimate the frame rate or configure DSI properly — I’m stuck.
Is there a reliable method to empirically find working H/V timing values?
The display I'm using is: RF3500D-AYW-MNG1-000
Is there anything that needs to be configured in the ILI9881C controller to make this work properly?
In the main code, I simply write to the framebuffer at 0xC0000000, then call HAL_DSI_Start(). No other logic is running yet.
Any help or working example would be greatly appreciated :folded_hands:
static void MX_DSIHOST_DSI_Init(void)
{
/* USER CODE BEGIN DSIHOST_Init 0 */
/* USER CODE END DSIHOST_Init 0 */
DSI_PLLInitTypeDef PLLInit = {0};
DSI_HOST_TimeoutTypeDef HostTimeouts = {0};
DSI_PHY_TimerTypeDef PhyTimings = {0};
DSI_VidCfgTypeDef VidCfg = {0};
/* USER CODE BEGIN DSIHOST_Init 1 */
/* USER CODE END DSIHOST_Init 1 */
hdsi.Instance = DSI;
hdsi.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE;
hdsi.Init.TXEscapeCkdiv = 4;
hdsi.Init.NumberOfLanes = DSI_TWO_DATA_LANES;
PLLInit.PLLNDIV = 20;
PLLInit.PLLIDF = DSI_PLL_IN_DIV1;
PLLInit.PLLODF = DSI_PLL_OUT_DIV1;
if (HAL_DSI_Init(&hdsi, &PLLInit) != HAL_OK)
{
Error_Handler();
}
HostTimeouts.TimeoutCkdiv = 1;
HostTimeouts.HighSpeedTransmissionTimeout = 0;
HostTimeouts.LowPowerReceptionTimeout = 0;
HostTimeouts.HighSpeedReadTimeout = 0;
HostTimeouts.LowPowerReadTimeout = 0;
HostTimeouts.HighSpeedWriteTimeout = 0;
HostTimeouts.HighSpeedWritePrespMode = DSI_HS_PM_DISABLE;
HostTimeouts.LowPowerWriteTimeout = 0;
HostTimeouts.BTATimeout = 0;
if (HAL_DSI_ConfigHostTimeouts(&hdsi, &HostTimeouts) != HAL_OK)
{
Error_Handler();
}
PhyTimings.ClockLaneHS2LPTime = 20;
PhyTimings.ClockLaneLP2HSTime = 18;
PhyTimings.DataLaneHS2LPTime = 10;
PhyTimings.DataLaneLP2HSTime = 13;
PhyTimings.DataLaneMaxReadTime = 0;
PhyTimings.StopWaitTime = 0;
if (HAL_DSI_ConfigPhyTimer(&hdsi, &PhyTimings) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_ConfigFlowControl(&hdsi, DSI_FLOW_CONTROL_BTA) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetLowPowerRXFilter(&hdsi, 10000) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_ConfigErrorMonitor(&hdsi, HAL_DSI_ERROR_NONE) != HAL_OK)
{
Error_Handler();
}
VidCfg.VirtualChannelID = 0;
VidCfg.ColorCoding = DSI_RGB888;
VidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE;
VidCfg.Mode = DSI_VID_MODE_BURST;
VidCfg.PacketSize = 720;
VidCfg.NumberOfChunks = 1;
VidCfg.NullPacketSize = 0;
VidCfg.HSPolarity = DSI_HSYNC_ACTIVE_LOW;
VidCfg.VSPolarity = DSI_VSYNC_ACTIVE_LOW;
VidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
VidCfg.HorizontalSyncActive = (ILI9881C_720X1280_HSYNC * 62500U)/27429U;
VidCfg.HorizontalBackPorch = (ILI9881C_720X1280_HBP * 62500U)/27429U;
VidCfg.HorizontalLine = ((720 + ILI9881C_720X1280_HSYNC + ILI9881C_720X1280_HBP + ILI9881C_720X1280_HFP) * 62500U)/27429U;
VidCfg.VerticalSyncActive = ILI9881C_720X1280_VSYNC;
VidCfg.VerticalBackPorch = ILI9881C_720X1280_VBP;
VidCfg.VerticalFrontPorch = ILI9881C_720X1280_VFP;
VidCfg.VerticalActive = 1280;
VidCfg.LPCommandEnable = DSI_LP_COMMAND_DISABLE;
VidCfg.LPLargestPacketSize = 0;
VidCfg.LPVACTLargestPacketSize = 0;
VidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
VidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
VidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
VidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
VidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
VidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
VidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_DISABLE;
if (HAL_DSI_ConfigVideoMode(&hdsi, &VidCfg) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetGenericVCID(&hdsi, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN DSIHOST_Init 2 */
RCC_PeriphCLKInitTypeDef PeriphClkInit;
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_DSI;
PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PHY;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
/* USER CODE END DSIHOST_Init 2 */
}
static void MX_LTDC_Init(void)
{
/* USER CODE BEGIN LTDC_Init 0 */
__HAL_RCC_LTDC_CLK_ENABLE();
/* USER CODE END LTDC_Init 0 */
LTDC_LayerCfgTypeDef pLayerCfg = {0};
/* USER CODE BEGIN LTDC_Init 1 */
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/* Configura PLL3 per fornire clock a LTDC */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLL3.PLL3M = 1; //5; //27.5Mhz
PeriphClkInitStruct.PLL3.PLL3N = 6; //132;
PeriphClkInitStruct.PLL3.PLL3R = 3; //3;
PeriphClkInitStruct.PLL3.PLL3P = 2; //2;
PeriphClkInitStruct.PLL3.PLL3Q = 2; //24;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_1;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOMEDIUM;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* USER CODE END LTDC_Init 1 */
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AH;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = ILI9881C_720X1280_HSYNC - 1;
hltdc.Init.VerticalSync = ILI9881C_720X1280_VSYNC - 1;
hltdc.Init.AccumulatedHBP = ILI9881C_720X1280_HSYNC + ILI9881C_720X1280_HBP - 1;
hltdc.Init.AccumulatedVBP = ILI9881C_720X1280_VSYNC + ILI9881C_720X1280_VBP - 1;
hltdc.Init.AccumulatedActiveW = ILI9881C_720X1280_HSYNC + 720 + ILI9881C_720X1280_HBP - 1;
hltdc.Init.AccumulatedActiveH = ILI9881C_720X1280_VSYNC + 1280 + ILI9881C_720X1280_VBP - 1;
hltdc.Init.TotalWidth = ILI9881C_720X1280_HSYNC + 720 + ILI9881C_720X1280_HBP + ILI9881C_720X1280_HFP - 1;
hltdc.Init.TotalHeigh = ILI9881C_720X1280_VSYNC + 1280 + ILI9881C_720X1280_VBP + ILI9881C_720X1280_VFP - 1;
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 = 720;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 1280;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
pLayerCfg.FBStartAdress = 0xC0000000;
pLayerCfg.ImageWidth = 720;
pLayerCfg.ImageHeight = 1280;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */
/* USER CODE END LTDC_Init 2 */
}
- Labels:
-
LCD-LTDC
-
STM32H7 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2025-05-09 12:50 AM
Hello @jacopo_93re
Please refer to the example TouchGFX available on Projects/STM32H743I-EVAL/Demonstrations to configure your LTDC peripheral.
Saket_Om
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2025-05-09 3:56 AM - edited 2025-05-09 3:57 AM
Hello @jacopo_93re,
I also recommend checking out the example available at the following path: LCD_DSI_VideoMode_SingleBuffer: This example operates with the ARGB8888 format.
But you can convert the LCD_DSI_VideoMode example from ARGB8888 to RGB888 by following these steps:
- In “main.c”:
- Modify the “CopyBuffer” function: Change “uint32_t destination = (uint32_t)pDst + (y * LCD_X_Size + x) * 3;// replace 4 with 3.
- Set “hdma2d.Init.ColorMode” to “DMA2D_OUTPUT_RGB888”.
- Set “hdma2d.LayerCfg[1].InputColorMode” to “DMA2D_INPUT_RGB888”.
- In “stm32h747i_discovery_lcd.c”:
- Change “Layercfg.PixelFormat” to “LTDC_PIXEL_FORMAT_RGB888”.
- Set “hdma2d_discovery.Init.ColorMode” to “DMA2D_OUTPUT_RGB888”.
- Ensure that the image data you are using is in the RGB888 format.
I hope this information is helpful. If it resolves your query, please mark this topic as the solution to assist others in finding the answer more quickly. Thank you for your contribution.
Best regards,
Dor_RH
