Initialize RTC on STM32F746

Hello, thanks for helping me.

Description

I am trying to setup the RTC and other peripherals for my STM32F746 Discovery board using the example project for the STM32F746 port of LVGL, I have gotten my UI running on the board.
However, as soon as I add a peripheral initialization function to main.c, when I try setting it up I get thrown into the error handler.

What MCU/Processor/Board and compiler are you using?

I am using An STM32F746 Discovery

What LVGL version are you using?

Latest

What do you want to achieve?

I want to be able to set up the RTC and other peripherals while using the STM32F746 Discovery port of LVGL

What have you tried so far?

I have tried generating initialization functions for the peripherals using STM32CUBEMX (which will compile and run correctly if I use a clean CubeIDE project), also tried debugging but I was unable to find what’s wrong…

Code to reproduce

This won’t run in the simulator, as it is for the specific board I’m trying to use this on.

// This function was already in the original LVGL port, I added a couple lines at the end for the RTC
static void SystemClock_Config(void)
{
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

    __HAL_RCC_PWR_CLK_ENABLE();

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 25;
    RCC_OscInitStruct.PLL.PLLN = 400;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 8;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    HAL_PWREx_EnableOverDrive();

    RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);

    // These lines were added by me for the RTC
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
    PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
}

//RTC Initialization function from STM32CUBEMX
static void MX_RTC_Init(void)
{
  
  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};

  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {	
    // THIS FUNCTION GETS CALLED AT THIS POINT ACCORDING TO DEBUGGER, MEANING HAL_RTC_INIT DOES NOT RETURN HAL_OK
    Error_Handler(); 
  }

  // Function is longer, but it would be useless to post the rest

}

MX_RTC_Init() is called right after SystemClock_Config(); in main().

Thanks for heping me.

The best solution I have found for a Cube issue like this is to step through HAL_RTC_Init and find why it does not return OK. Unfortunately the error code on its own is not very useful.

My guess here is that the clocking is still not correct for some reason.

I would suppose there is something missing in SystemClock_Config.

You can do the following:
Take the CubeMX save the generated output when you enable the RTC to new directory,
and than take CubeMX disable the RTC and let CubeMX generate the code.
And then compare the code of the two outputs (e.g. with WinMerge or equivalent).

I’m back after trying different things a couple days.
I did both the recommendations, couldn’t pinpoint what was wrong still.
Here’s something odd:
If I run a blank project created with STM32CubeIDEthat initializes the rtc, then run the lvgl project, the initialization function is able to complete, still the RTC won’t work.

Any suggestions what to try will be greatly appreciated.

To recapitulate:

You start the project with the main which was generated by CubeMX.
So this calls the SystemClock_Config and in advance the MX_RTC_Init which is also generated by CubeMX.
The HAL_RTC_Init within MX_RTC_Init is doing OK as the system clock is proberly setup.

What do you do next? What do you call from the STM32F746 lvgl project?
Just to be sure, not the SystemClock_Config which is provided by the lvgl STMF746 project!?

I just re-read my own post and it’s awfully written and ambiguous, sorry, guess frustration got the better of me.
I created a blank project with STM32CubeIDE and generated lock and RTC init functions within those projects.
I run said project on the board, everything fine.
If I flash and run the LVGL project with a clockconfig and RTC config carried over from the blank project immediately afterwards, at least the RTC config function returns correctly, however the RTC isn’t really running.
If I flash the blank project and then disconnect the board, reset it or let it be a couple mins and then flash and run the LVGL project as described above, I still get HAL_Error from the RTC init function.
This is all really odd to me.
Thanks.

You wrote, that you tried my recommendation but you couldn’t find a solution.
So, its not clear to me whether you didn’t find the missing settings,
or you did find the difference, but it doesn’t lead to a working RTC.

To be clear, besides the three lines you added to the end of SystemClock_Config, there is one line to change and one line to add.

The changed line:

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSI;

The line to add (before the call of HAL_RCC_OscConfig (…):

 RCC_OscInitStruct.LSIState = RCC_LSI_ON;

This is if you use the internal low speed oscillator for the RTC. You can also use the external low speed oscillator, but you have to setup the GPIOs PC14 and PC15 accordingly.

Yes, I did add those two extra lines, basically did a line by line comparison, it still didn’t work, I haven’t tried the external oscillator.

If the code is 100% identical between the two projects but it still doesn’t work properly, I would now begin to suspect that this is another one of the obscure bugs one can easily find in Cube.

Perhaps compare the optimization settings between the empty project and our project. Maybe Cube is getting broken by -Os.

Thanks for your reply and hanging on with me.
I just tried -O0. had no success.
This is very strange, I also tried changing SystemClock_Config to use HSI @216 MHz, my LVGL app runs fine until I uncomment the MX_RTC_Init function.

I wonder if the Cube versions are the same. We ship our own version of Cube in lv_port_stm32f746_disco (under the HAL_Driver directory). It might be worth trying to overwrite that with whatever your other project supplies.

I just tried replacing the Cube drivers as you suggested.
I still get the same result unfotunately.
UPDATE: I cloned a new fresh copy of the port from github to see if I changed something inadvertently and messed up.
Only added code required for Systemclock and RTC initialization to it.
Still nothing.
The point where everything seems to go south seems to be the following:

 while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
    {
      if((HAL_GetTick() - tickstart ) > RTC_TIMEOUT_VALUE)
      {       
        return HAL_TIMEOUT;
      } 
    }

Which lives inside HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef* hrtc)

Here’s something that might work, although I haven’t checked the Cube RTC implementation to see whether it suffers from this oversight.

Try adding this before the while loop:

__asm volatile("DSB\n"); /* force memory write */

I added the line, still wasn’t able to get it to work.

Do you have this code anywhere in your project?

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{

  if(rtcHandle->Instance==RTC)
  {
  /* USER CODE BEGIN RTC_MspInit 0 */

  /* USER CODE END RTC_MspInit 0 */
    /* RTC clock enable */
    __HAL_RCC_RTC_ENABLE();
  /* USER CODE BEGIN RTC_MspInit 1 */

  /* USER CODE END RTC_MspInit 1 */
  }
}

And also this should be anywhere:

void HAL_MspInit(void)
{
  /* USER CODE BEGIN MspInit 0 */

  /* USER CODE END MspInit 0 */

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_RCC_SYSCFG_CLK_ENABLE();

  /* System interrupt init*/

  /* USER CODE BEGIN MspInit 1 */

  /* USER CODE END MspInit 1 */
}

Those two seem to be unimplemented, makes no sense, if HAL_MspInit wasn’t there, then nothing would work and I wouldn’t even be able to run LVGL, right?

There is only a standard empty ‘__weak’ implementation for HAL_RTC_MspInit and HAL_MspInit if RTC is not used.
CubeMX generates a ‘real’ implementation if it is used.
If these two functions (with real implementation/content) are missing, the compiler will not complain as the weak funktions are existing. But RTC will not work.

According a setting of CubeMX the real implementations of these functions will be generated in stm32f7xx_hal_msp.c or in stm32f7xx_hal_msp.c plus interface specific files (e.g. rtc.c/h).

1 Like