LTDC + DSI Video Mode - No Display
I am attempting to display to an ILI9881C based panel. After successfully initialising and testing the panel using DSI only, I am working on DSI Video mode to pull data from a frame buffer via LTDC.
I have the DSI configured as follows
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_ENABLE;
hdsi.Init.TXEscapeCkdiv = 4;
hdsi.Init.NumberOfLanes = DSI_TWO_DATA_LANES;
PLLInit.PLLNDIV = 119;
PLLInit.PLLIDF = DSI_PLL_IN_DIV3;
PLLInit.PLLODF = DSI_PLL_OUT_DIV2;
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 = 23;
PhyTimings.ClockLaneLP2HSTime = 33;
PhyTimings.DataLaneHS2LPTime = 14;
PhyTimings.DataLaneLP2HSTime = 26;
PhyTimings.DataLaneMaxReadTime = 100;
PhyTimings.StopWaitTime = 10;
if (HAL_DSI_ConfigPhyTimer(&hdsi, &PhyTimings) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_TCLK_POST, ENABLE, 35) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_TLPX_CLK, ENABLE, 120) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_THS_EXIT, ENABLE, 150) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_TLPX_DATA, ENABLE, 120) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_THS_TRAIL, ENABLE, 140) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_THS_PREPARE, ENABLE, 126) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetPHYTimings(&hdsi, DSI_TCLK_PREPARE, ENABLE, 100) != 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_SetLanePinsConfiguration(&hdsi, DSI_SWAP_LANE_PINS, DSI_CLOCK_LANE, ENABLE) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetLanePinsConfiguration(&hdsi, DSI_SWAP_LANE_PINS, DSI_DATA_LANE0, ENABLE) != HAL_OK)
{
Error_Handler();
}
if (HAL_DSI_SetLanePinsConfiguration(&hdsi, DSI_SWAP_LANE_PINS, DSI_DATA_LANE1, ENABLE) != 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 = 0;
VidCfg.NullPacketSize = 5;
VidCfg.HSPolarity = DSI_HSYNC_ACTIVE_LOW;
VidCfg.VSPolarity = DSI_VSYNC_ACTIVE_LOW;
VidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
VidCfg.HorizontalSyncActive = 5;
VidCfg.HorizontalBackPorch = 29;
VidCfg.HorizontalLine = 1795;
VidCfg.VerticalSyncActive = 2;
VidCfg.VerticalBackPorch = 14;
VidCfg.VerticalFrontPorch = 8;
VidCfg.VerticalActive = 1280;
VidCfg.LPCommandEnable = DSI_LP_COMMAND_DISABLE;
VidCfg.LPLargestPacketSize = 20;
VidCfg.LPVACTLargestPacketSize = 20;
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_ENABLE;
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 */
if(HAL_DSI_Start(&hdsi)!= HAL_OK)
{
Error_Handler();
}
RCC_PeriphCLKInitTypeDef PeriphClkInit;
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_DSI;
PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PHY;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
/* USER CODE END DSIHOST_Init 2 */
}
And the LTDC as follows
static void MX_LTDC_Init(void)
{
/* USER CODE BEGIN LTDC_Init 0 */
/* USER CODE END LTDC_Init 0 */
LTDC_LayerCfgTypeDef pLayerCfg = {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 = 13;
hltdc.Init.AccumulatedVBP = 15;
hltdc.Init.AccumulatedActiveW = 733;
hltdc.Init.AccumulatedActiveH = 1295;
hltdc.Init.TotalWidth = 751;
hltdc.Init.TotalHeigh = 1303;
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_RGB888;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
pLayerCfg.FBStartAdress = 0xD0000000;
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 */
__HAL_DSI_WRAPPER_DISABLE(&hdsi);
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_RESET); //Reset the driver chip
HAL_Delay(5);
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_SET);
HAL_Delay(125);
/* Configure the audio driver */
IOCtx.Address = 0;
IOCtx.GetTick = BSP_GetTick;
IOCtx.WriteReg = DSI_IO_Write;
IOCtx.ReadReg = DSI_IO_Read;
ILI9881C_RegisterBusIO(&ILI9881CObj, &IOCtx);
ILI9881C_Init(&ILI9881CObj ,ILI9881C_FORMAT_RGB888, ILI9881C_ORIENTATION_LANDSCAPE); //Initialise
__HAL_DSI_WRAPPER_ENABLE(&hdsi);
//HAL_DSI_PatternGeneratorStart(&hdsi, 0, 0);
/* USER CODE END LTDC_Init 2 */
}
When the program runs, I can see the LTDC ticking in the SFR viewer, but no image is displayed on the screen, which is turned on, backlit and will have been initialised at the end of the LTDC startup code.
I have tried the following:
- Enabling LP transitions during all periods (seemingly required for sending commands in video mode)
- Reducing the LTDC pixel clock, as I'm only aiming for 20Hz frame rate
- Testing all combinations of HSYNC and VSYNC signal polarity
- Testing Non-burst and burst modes of DSI video (all modes available in ILI9881C)
At this point I can't even narrow down where the issue lies! I believe my DSI PHY timings to be correct, as I assume I wouldn't be able to send commands if they weren't.
Another issue is that the DSI Read command does not work in Video mode. This means that I can't validate my settings before enabling the LTDC to start the video stream.
