cancel
Showing results for 
Search instead for 
Did you mean: 

Use LTDC with DSI on STM32L4R9

ebray
Associate II

I have a custom board with an STM32L4R9 connected to a display (320x480) with internal GRAM over DSI. I've been successful in configuring and controlling the display using the HAL DSI API. Now I would like to use the LTDC to feed the DSI controller but have not been successful in getting anything to show up on the display.

The LTDC is configured with:

Display Type: RGB666 (18 bits) - DSI Mode

Layer 0 Pixel Format: RGB565 (corresponding to TouchGFX)

I'm trying to use the LTDC as follows:

  uint16_t buf565[320*480];
 
  for (uint32_t i = 0; i < (320 * 480); i++)
  {
	  buf565[i] = 0x1f00;
  }
 
  LTDC_LayerCfgTypeDef pLayerCfg = {0};
 
  pLayerCfg.WindowX0 = 0;
	pLayerCfg.WindowX1 = 320;
	pLayerCfg.WindowY0 = 0;
	pLayerCfg.WindowY1 = 480;
	pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
	pLayerCfg.Alpha = 0;
	pLayerCfg.Alpha0 = 0;
	pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
	pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
	pLayerCfg.FBStartAdress = (uint32_t) buf565;
	pLayerCfg.ImageWidth = 320;
	pLayerCfg.ImageHeight = 480;
	pLayerCfg.Backcolor.Blue = 0;
	pLayerCfg.Backcolor.Green = 0;
	pLayerCfg.Backcolor.Red = 0;
	HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0);
 
	HAL_DSI_Refresh(&hdsi);

Any help in figuring out where I'm going wrong would be greatly appreciated!

9 REPLIES 9
MM..1
Chief II

You need full LTDC config not only layer.

Sure. That's handled in this CubeMX generated function.

void MX_LTDC_Init(void)
{
  LTDC_LayerCfgTypeDef pLayerCfg = {0};
  LTDC_LayerCfgTypeDef pLayerCfg1 = {0};
 
  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 = 0;
  hltdc.Init.VerticalSync = 0;
  hltdc.Init.AccumulatedHBP = 1;
  hltdc.Init.AccumulatedVBP = 1;
  hltdc.Init.AccumulatedActiveW = 321;
  hltdc.Init.AccumulatedActiveH = 481;
  hltdc.Init.TotalWidth = 322;
  hltdc.Init.TotalHeigh = 482;
  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 = 320;
  pLayerCfg.WindowY0 = 0;
  pLayerCfg.WindowY1 = 480;
  pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
  pLayerCfg.Alpha = 0;
  pLayerCfg.Alpha0 = 0;
  pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
  pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
  pLayerCfg.FBStartAdress = 0;
  pLayerCfg.ImageWidth = 0;
  pLayerCfg.ImageHeight = 0;
  pLayerCfg.Backcolor.Blue = 0;
  pLayerCfg.Backcolor.Green = 0;
  pLayerCfg.Backcolor.Red = 0;
  if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
  {
    Error_Handler();
  }
  pLayerCfg1.WindowX0 = 0;
  pLayerCfg1.WindowX1 = 0;
  pLayerCfg1.WindowY0 = 0;
  pLayerCfg1.WindowY1 = 0;
  pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
  pLayerCfg1.Alpha = 0;
  pLayerCfg1.Alpha0 = 0;
  pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
  pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
  pLayerCfg1.FBStartAdress = 0;
  pLayerCfg1.ImageWidth = 0;
  pLayerCfg1.ImageHeight = 0;
  pLayerCfg1.Backcolor.Blue = 0;
  pLayerCfg1.Backcolor.Green = 0;
  pLayerCfg1.Backcolor.Red = 0;
  if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_LTDC_SetPitch(&hltdc, 0, 0) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_LTDC_SetPitch(&hltdc, 0, 1) != HAL_OK)
  {
    Error_Handler();
  }
 
}

MM..1
Chief II

TouchGFX use only one layer and Cube generate bad MX , you need remove Layer1 parts. Too i see problem in HSYNC = 0 and VSYNC = 0

DSI need i mean proper config to counterparts in DSI part. And you write about display with internal GRAM, then DSI can work in more modes ...

LTDC is primary used for video mode. Try read about partial framebuffers. Too for better picture i recommend use RGB888 over DSI instead 666 565.

According to the ST documentation (DSIHOST presentation and AN4860) using LTDC with DSI in Adapted Command Mode is the most efficient way to control a display with internal GRAM. That's exactly what I'm trying to do. I believe HSYNC and VSYNC are solely related to Video mode which wouldn't apply.

I assumed since the window for the second layer was 0,0,0,0 it wouldn't have any impact. I test this by commenting out those sections of the function but there was no change in functionality.

I am familiar with partial frame buffers as well as the merits of different pixel formats which I can consider once I have the display functional.

MM..1
Chief II

Try compare your code with any TouchGFX demo for 469DISCO , this have DSI with Adapted with TE, but i mean DSI in Adapted mode too need sync pulses from LTDC.

I did compare with the DSI example project and it appears that the code generated by CubeMX for the LTDC configuration is consistent as the example shows 0 for the HSYNC and VSYNC values.

 0693W000005AYBmQAO.jpg 

You show CubeFW example, but i speak about Touchgfx generated examples, this show part from my 4.15 when i select 469DISCO as target,

for your display is this better example as when i generate same way over TouchGFX without cube example for L4R9, where you have right sync is 0 for 390x390 display but MX_DSIHOST_DSI_Init have big diference for this two displays examples. Too 4R9 uses GFXMMU ...

/**

 * @brief LTDC Initialization Function

 * @param None

 * @retval None

 */

static void MX_LTDC_Init(void)

{

 /* USER CODE BEGIN LTDC_Init 0 */

 /* USER CODE END LTDC_Init 0 */

 LTDC_LayerCfgTypeDef pLayerCfg = {0};

 LTDC_LayerCfgTypeDef pLayerCfg1 = {0};

 /* USER CODE BEGIN LTDC_Init 1 */

 /* USER CODE END LTDC_Init 1 */

 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 = 1;

 hltdc.Init.VerticalSync = 1;

 hltdc.Init.AccumulatedHBP = 2;

 hltdc.Init.AccumulatedVBP = 2;

 hltdc.Init.AccumulatedActiveW = 202;

 hltdc.Init.AccumulatedActiveH = 482;

 hltdc.Init.TotalWidth = 203;

 hltdc.Init.TotalHeigh = 483;

 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 = 200;

 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 = 0xC0000000;

 pLayerCfg.ImageWidth = 200;

 pLayerCfg.ImageHeight = 480;

 pLayerCfg.Backcolor.Blue = 0;

 pLayerCfg.Backcolor.Green = 0;

 pLayerCfg.Backcolor.Red = 0;

 if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)

 {

  Error_Handler();

 }

 pLayerCfg1.WindowX0 = 0;

 pLayerCfg1.WindowX1 = 0;

 pLayerCfg1.WindowY0 = 0;

 pLayerCfg1.WindowY1 = 0;

 pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;

 pLayerCfg1.Alpha = 0;

 pLayerCfg1.Alpha0 = 0;

 pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;

 pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;

 pLayerCfg1.FBStartAdress = 0;

 pLayerCfg1.ImageWidth = 0;

 pLayerCfg1.ImageHeight = 0;

 pLayerCfg1.Backcolor.Blue = 0;

 pLayerCfg1.Backcolor.Green = 0;

 pLayerCfg1.Backcolor.Red = 0;

 if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN LTDC_Init 2 */

 __HAL_LTDC_DISABLE(&hltdc);

 DSI_LPCmdTypeDef LPCmd;

 HAL_DSI_Start(&hdsi);

 OTM8009A_Init(OTM8009A_FORMAT_RBG565, LCD_ORIENTATION_LANDSCAPE);

 HAL_DSI_ShortWrite(&hdsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, OTM8009A_CMD_DISPOFF, 0x00);

 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(&hdsi, &LPCmd);

 HAL_LTDC_SetPitch(&hltdc, 800, 0);

 __HAL_LTDC_ENABLE(&hltdc);

 /* USER CODE END LTDC_Init 2 */

}

ebray
Associate II

The only significant differences I see are the changes introduced by setting VSYNC and HSYNC to 1.

hltdc.Init.HorizontalSync = 1;
 hltdc.Init.VerticalSync = 1;
 hltdc.Init.AccumulatedHBP = 2;
 hltdc.Init.AccumulatedVBP = 2;
 hltdc.Init.AccumulatedActiveW = 202;
 hltdc.Init.AccumulatedActiveH = 482;
 hltdc.Init.TotalWidth = 203;
 hltdc.Init.TotalHeigh = 483;

Using the same logic, I modified my code but observed no difference in the output.

MM..1
Chief II

I mean this is big difference

 __HAL_LTDC_DISABLE(&hltdc);

 DSI_LPCmdTypeDef LPCmd;

 HAL_DSI_Start(&hdsi);

 OTM8009A_Init(OTM8009A_FORMAT_RBG565, LCD_ORIENTATION_LANDSCAPE);

 HAL_DSI_ShortWrite(&hdsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, OTM8009A_CMD_DISPOFF, 0x00);

 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(&hdsi, &LPCmd);

 HAL_LTDC_SetPitch(&hltdc, 800, 0);

 __HAL_LTDC_ENABLE(&hltdc);

and bigger is when you compare MX_DSIHOST_DSI_Init

But as i write in other tickets , when you start DSI you for checking config use call HAL_DSI_PatternGeneratorStart(&hdsi, 0, 0);...