2020-05-12 07:21 AM
Hello!
I'm using the Cube IDE with STM32H753 and trying to initialize the LTDC from HAL.
I already did this with success for the STM32F767.
But for the STM32H753 I have some problems with LTDC drivers.
The programm hangs up during debugging on the automatic genarated initialization routine.
The main looks like this:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LTDC_Init();
And the problem is the MX_LTDC_Init();
The program goes into it (inside the ltdc.c file):
void MX_LTDC_Init(void)
{
LTDC_LayerCfgTypeDef pLayerCfg = {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 = 9;
hltdc.Init.VerticalSync = 1;
hltdc.Init.AccumulatedHBP = 29;
hltdc.Init.AccumulatedVBP = 5;
hltdc.Init.AccumulatedActiveW = 269;
hltdc.Init.AccumulatedActiveH = 325;
hltdc.Init.TotalWidth = 279;
hltdc.Init.TotalHeigh = 329;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 200;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = 240;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 320;
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 = 0;
pLayerCfg.ImageWidth = 220;
pLayerCfg.ImageHeight = 320;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 250;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
}
And then hangs on the HAL_LTDC_Init line.
Going further into that it looks like the problem is with the line 58:
HAL_StatusTypeDef HAL_LTDC_Init(LTDC_HandleTypeDef *hltdc)
{
uint32_t tmp, tmp1;
/* Check the LTDC peripheral state */
if (hltdc == NULL)
{
return HAL_ERROR;
}
/* Check function parameters */
assert_param(IS_LTDC_ALL_INSTANCE(hltdc->Instance));
assert_param(IS_LTDC_HSYNC(hltdc->Init.HorizontalSync));
assert_param(IS_LTDC_VSYNC(hltdc->Init.VerticalSync));
assert_param(IS_LTDC_AHBP(hltdc->Init.AccumulatedHBP));
assert_param(IS_LTDC_AVBP(hltdc->Init.AccumulatedVBP));
assert_param(IS_LTDC_AAH(hltdc->Init.AccumulatedActiveH));
assert_param(IS_LTDC_AAW(hltdc->Init.AccumulatedActiveW));
assert_param(IS_LTDC_TOTALH(hltdc->Init.TotalHeigh));
assert_param(IS_LTDC_TOTALW(hltdc->Init.TotalWidth));
assert_param(IS_LTDC_HSPOL(hltdc->Init.HSPolarity));
assert_param(IS_LTDC_VSPOL(hltdc->Init.VSPolarity));
assert_param(IS_LTDC_DEPOL(hltdc->Init.DEPolarity));
assert_param(IS_LTDC_PCPOL(hltdc->Init.PCPolarity));
#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1)
if (hltdc->State == HAL_LTDC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hltdc->Lock = HAL_UNLOCKED;
/* Reset the LTDC callback to the legacy weak callbacks */
hltdc->LineEventCallback = HAL_LTDC_LineEventCallback; /* Legacy weak LineEventCallback */
hltdc->ReloadEventCallback = HAL_LTDC_ReloadEventCallback; /* Legacy weak ReloadEventCallback */
hltdc->ErrorCallback = HAL_LTDC_ErrorCallback; /* Legacy weak ErrorCallback */
if (hltdc->MspInitCallback == NULL)
{
hltdc->MspInitCallback = HAL_LTDC_MspInit;
}
/* Init the low level hardware */
hltdc->MspInitCallback(hltdc);
}
#else
if (hltdc->State == HAL_LTDC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hltdc->Lock = HAL_UNLOCKED;
/* Init the low level hardware */
HAL_LTDC_MspInit(hltdc);
}
#endif /* USE_HAL_LTDC_REGISTER_CALLBACKS */
/* Change LTDC peripheral state */
hltdc->State = HAL_LTDC_STATE_BUSY;
/* Configure the HS, VS, DE and PC polarity */
hltdc->Instance->GCR &= ~(LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL | LTDC_GCR_PCPOL);
hltdc->Instance->GCR |= (uint32_t)(hltdc->Init.HSPolarity | hltdc->Init.VSPolarity | \
hltdc->Init.DEPolarity | hltdc->Init.PCPolarity);
The debugger says this:
So it looks like the Instance is initialized with zeros. But why?
Like I wrote , the code is automatic generated, so I don't delete anythig or write anything into the Init functions.
How can I deep deeper to see what could be the problem?
The application shall just display a simple one color picture first.
Thank you and regards,
Gregor
2020-05-12 10:45 AM
>>So it looks like the Instance is initialized with zeros. But why?
Got the right AHB, APB, PLL and peripheral clocks initialized/enabled properly?
Check that the startup code is properly initializing the statics.
Check you don't have different WEAK functions competing to get bound by the linker.
Disassemble code determine what code gets into the final image, and what's getting executed.
2020-05-12 12:45 PM
Hi!
Thank you for the reply!
So, to get to each point from your answer.
1. My clock initializations seems to be ok. Here is the screen shot:
The source is the 25MHz input clock. The LTDC is getting 8.33 MHz, but this shouldn't be a problem I think.
This constellation works with a blinking LED :)
I also get a warning on the RCC because I'm using the 4wire JTAG as a debugg:
2. I don't know how to check the statics? But I have discovered, that in the mentioned code:
HAL_StatusTypeDef HAL_LTDC_Init(LTDC_HandleTypeDef *hltdc)
{
uint32_t tmp, tmp1;
/* Check the LTDC peripheral state */
if (hltdc == NULL)
{
return HAL_ERROR;
}
/* Check function parameters */
assert_param(IS_LTDC_ALL_INSTANCE(hltdc->Instance));
assert_param(IS_LTDC_HSYNC(hltdc->Init.HorizontalSync));
assert_param(IS_LTDC_VSYNC(hltdc->Init.VerticalSync));
assert_param(IS_LTDC_AHBP(hltdc->Init.AccumulatedHBP));
assert_param(IS_LTDC_AVBP(hltdc->Init.AccumulatedVBP));
assert_param(IS_LTDC_AAH(hltdc->Init.AccumulatedActiveH));
assert_param(IS_LTDC_AAW(hltdc->Init.AccumulatedActiveW));
assert_param(IS_LTDC_TOTALH(hltdc->Init.TotalHeigh));
assert_param(IS_LTDC_TOTALW(hltdc->Init.TotalWidth));
assert_param(IS_LTDC_HSPOL(hltdc->Init.HSPolarity));
assert_param(IS_LTDC_VSPOL(hltdc->Init.VSPolarity));
assert_param(IS_LTDC_DEPOL(hltdc->Init.DEPolarity));
assert_param(IS_LTDC_PCPOL(hltdc->Init.PCPolarity));
#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1)
if (hltdc->State == HAL_LTDC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hltdc->Lock = HAL_UNLOCKED;
/* Reset the LTDC callback to the legacy weak callbacks */
hltdc->LineEventCallback = HAL_LTDC_LineEventCallback; /* Legacy weak LineEventCallback */
hltdc->ReloadEventCallback = HAL_LTDC_ReloadEventCallback; /* Legacy weak ReloadEventCallback */
hltdc->ErrorCallback = HAL_LTDC_ErrorCallback; /* Legacy weak ErrorCallback */
if (hltdc->MspInitCallback == NULL)
{
hltdc->MspInitCallback = HAL_LTDC_MspInit;
}
/* Init the low level hardware */
hltdc->MspInitCallback(hltdc);
}
#else
if (hltdc->State == HAL_LTDC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hltdc->Lock = HAL_UNLOCKED;
/* Init the low level hardware */
HAL_LTDC_MspInit(hltdc);
}
#endif /* USE_HAL_LTDC_REGISTER_CALLBACKS */
/* Change LTDC peripheral state */
hltdc->State = HAL_LTDC_STATE_BUSY;
/* Configure the HS, VS, DE and PC polarity */
hltdc->Instance->GCR &= ~(LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL | LTDC_GCR_PCPOL);
hltdc->Instance->GCR |= (uint32_t)(hltdc->Init.HSPolarity | hltdc->Init.VSPolarity | \
hltdc->Init.DEPolarity | hltdc->Init.PCPolarity);
The line 42 is responsible for resetting the initialized values:
/* Init the low level hardware */
hltdc->MspInitCallback(hltdc);
If I debugg one line before that, then I get the following (correct for my display) values:
So I think that the initialization is ok, right?
But when the code gets into the mentioned line 42, then something happens... -> see point 3.
3. Inside of the driver "stm32h7xx_hal_ltdc.c" there is a weak declaration of the mentioned function in the line 42:
__weak void HAL_LTDC_MspInit(LTDC_HandleTypeDef *hltdc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hltdc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_LTDC_MspDeInit could be implemented in the user file
*/
}
It seems that this function is called (by the satndard in the driver) and resets all the values !
Actually it shall be the function in the (also automatic genarted ltdc.c file, which shall initialize the low level hardware:
void HAL_LTDC_MspInit(LTDC_HandleTypeDef* ltdcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(ltdcHandle->Instance==LTDC)
{
/* USER CODE BEGIN LTDC_MspInit 0 */
/* USER CODE END LTDC_MspInit 0 */
/* LTDC clock enable */
__HAL_RCC_LTDC_CLK_ENABLE();
__HAL_RCC_GPIOK_CLK_ENABLE();
__HAL_RCC_GPIOJ_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
/**LTDC GPIO Configuration
PK5 ------> LTDC_B6
PK4 ------> LTDC_B5
PJ15 ------> LTDC_B3
PK6 ------> LTDC_B7
PK3 ------> LTDC_B4
PK7 ------> LTDC_DE
PJ14 ------> LTDC_B2
PI12 ------> LTDC_HSYNC
PI13 ------> LTDC_VSYNC
PI14 ------> LTDC_CLK
PK2 ------> LTDC_G7
PK0 ------> LTDC_G5
PK1 ------> LTDC_G6
PJ11 ------> LTDC_G4
PJ10 ------> LTDC_G3
PJ9 ------> LTDC_G2
PJ6 ------> LTDC_R7
PJ1 ------> LTDC_R2
PJ5 ------> LTDC_R6
PJ2 ------> LTDC_R3
PJ3 ------> LTDC_R4
PJ4 ------> LTDC_R5
*/
GPIO_InitStruct.Pin = TFT_B6_Pin|TFT_B5_Pin|TFT_B7_Pin|TFT_B4_Pin
|TFT_EN_Pin|TFT_G7_Pin|TFT_G5_Pin|TFT_G6_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);
GPIO_InitStruct.Pin = TFT_B3_Pin|TFT_B2_Pin|TFT_G4_Pin|TFT_G3_Pin
|TFT_G2_Pin|TFT_R7_Pin|TFT_R2_Pin|TFT_R6_Pin
|TFT_R3_Pin|TFT_R4_Pin|TFT_R5_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);
GPIO_InitStruct.Pin = TFT_HSYNC_Pin|TFT_VSYNC_Pin|TFT_CLK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/* LTDC interrupt Init */
HAL_NVIC_SetPriority(LTDC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LTDC_IRQn);
HAL_NVIC_SetPriority(LTDC_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LTDC_ER_IRQn);
/* USER CODE BEGIN LTDC_MspInit 1 */
/* USER CODE END LTDC_MspInit 1 */
}
}
So now I'm confused. Did I did something wrong with the driver? I haven't change a signle line of it...
4. I don't really know how, but could this be also the reason for the point 3?
Regards,
Gregor
2020-05-12 01:00 PM
Look at the hardware itself, not the CubeMX views, the code running on the device ultimately dictates what happens.
The statics are copied by code in, or called from, startup_stm32h7xx.s
Got an adequate stack size for local/auto variables in use?
And empty subroutine is not clearing your structure.
Walk the code that's being executed. Check if there is some memcpy(), memset(), or subroutine prologue code damaging the instance/structure.
2020-05-12 01:58 PM
Ok, I will do my best and share the results.
2020-05-13 12:30 PM
Hi!
So I did some stuff and found out that you were right about "And empty subroutine is not clearing your structure."
In this picture you can see that the line 261 was passed and the structure is still there:
But my question is still open: why the actual function, that shall be called in the ltdc.c file "HAL_LTDC_MspInit(hltdc)" is not beeing called?
Instead of it the weak function that is empty...
__weak void HAL_LTDC_MspInit(LTDC_HandleTypeDef *hltdc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hltdc);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_LTDC_MspInit could be implemented in the user file
*/
}
The generator adds the "real function" that initialize the low level hardware into the ltdc.c file:
void HAL_LTDC_MspInit(LTDC_HandleTypeDef* ltdcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(ltdcHandle->Instance==LTDC)
{
/* USER CODE BEGIN LTDC_MspInit 0 */
/* USER CODE END LTDC_MspInit 0 */
/* LTDC clock enable */
__HAL_RCC_LTDC_CLK_ENABLE();
__HAL_RCC_GPIOK_CLK_ENABLE();
__HAL_RCC_GPIOJ_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
/**LTDC GPIO Configuration
PK5 ------> LTDC_B6
PK4 ------> LTDC_B5
PJ15 ------> LTDC_B3
PK6 ------> LTDC_B7
PK3 ------> LTDC_B4
PK7 ------> LTDC_DE
PJ14 ------> LTDC_B2
PI12 ------> LTDC_HSYNC
PI13 ------> LTDC_VSYNC
PI14 ------> LTDC_CLK
PK2 ------> LTDC_G7
PK0 ------> LTDC_G5
PK1 ------> LTDC_G6
PJ11 ------> LTDC_G4
PJ10 ------> LTDC_G3
PJ9 ------> LTDC_G2
PJ6 ------> LTDC_R7
PJ1 ------> LTDC_R2
PJ5 ------> LTDC_R6
PJ2 ------> LTDC_R3
PJ3 ------> LTDC_R4
PJ4 ------> LTDC_R5
*/
GPIO_InitStruct.Pin = TFT_B6_Pin|TFT_B5_Pin|TFT_B7_Pin|TFT_B4_Pin
|TFT_EN_Pin|TFT_G7_Pin|TFT_G5_Pin|TFT_G6_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);
GPIO_InitStruct.Pin = TFT_B3_Pin|TFT_B2_Pin|TFT_G4_Pin|TFT_G3_Pin
|TFT_G2_Pin|TFT_R7_Pin|TFT_R2_Pin|TFT_R6_Pin
|TFT_R3_Pin|TFT_R4_Pin|TFT_R5_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);
GPIO_InitStruct.Pin = TFT_HSYNC_Pin|TFT_VSYNC_Pin|TFT_CLK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
/* LTDC interrupt Init */
HAL_NVIC_SetPriority(LTDC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LTDC_IRQn);
HAL_NVIC_SetPriority(LTDC_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LTDC_ER_IRQn);
/* USER CODE BEGIN LTDC_MspInit 1 */
/* USER CODE END LTDC_MspInit 1 */
}
}
This function is never being called...
I still don't know what is resetting the structure but I know that the line 269 from the picture above is trying to access a GPIO that should be defined by the "real function". So in other words, it try to deal with something that is not even initialized.
Is this a bug in the HAL drivers of STM?
Do I have to tell my program to use the "real initialization function" from the ltdc.c file instead of the weak empty function in the "stm32h7xx_hal_ltdc.c"?
Regards,
Gregor
2020-05-16 11:02 AM
Is there anything special about the STM32H753 that I need to consider?
Why the same board with the STM32F767 works perfectly (user code is 100% identical)?
Thank you for any hints...
2020-07-09 09:09 AM
Hi Gregory,
Did you find the solution on this ?
I have exactly the same problem.
Thanks in advance
Stathis
2020-07-09 01:06 PM
Hi!
No nobody could help me with this one...
STM also donsen't seems to bother about this.
Regards,
Gregor
2020-07-09 11:02 PM
Thanks for your fast reply.
I will try to solve it.