STM32 RTC Timeout during initialization

7

I am trying to initialize the RTC on a STM32F469I-DISCO board. Since I am still learning, I tried to play with the HAL API that allow me to achieve some projects till the day I'll get enough understanding of this microcontroller to play with registers directly.

Anyway, my code uses the STM32F469I-DISCO template from CubeF4 that allow to load directly the HAL layer and the system clock (180 MHz via the 8 MHz HSE oscillator).

In order to initialize the RTC, I followed the instructions given in the UM1725 : Description of STM32F4 HAL and LL drivers. Page 715, Section 55.2.4 you have instructions to use the HAL_RTC API.

And the first point says that it is necessary to enable the "RTC Domain Access". This point is explained in the section above (55.2.3, same page).

And I did what it is asked to do. Here is my code (simplified, I only let the RTC Init part and System Clock configuration):

#include "main.h"

RTC_HandleTypeDef rtcHandle;
RTC_InitTypeDef rtcInit;
RTC_TimeTypeDef rtcTime;
RTC_DateTypeDef rtcDate;

static void SystemClock_Config(void);
static void Error_Handler(void);


int main(void)
{
  HAL_Init();
  SystemClock_Config();

  ////////////////// RTC 

  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
  __HAL_RCC_RTC_ENABLE();

  rtcInit.HourFormat = RTC_HOURFORMAT_24;
  rtcInit.AsynchPrediv = 0x7F;
  rtcInit.SynchPrediv = 0xFF;
  rtcInit.OutPut = RTC_OUTPUT_DISABLE;
  rtcInit.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  rtcInit.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;

  rtcHandle.Instance = RTC;
  rtcHandle.Init = rtcInit;

  HAL_RTC_Init(&rtcHandle);

  rtcTime.Hours = 12;
  rtcTime.Minutes = 30;
  rtcTime.Seconds = 40;

  rtcDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
  rtcDate.Month = RTC_MONTH_APRIL;
  rtcDate.Date = 4;
  rtcDate.Year= 17;


  HAL_RTC_SetTime(&rtcHandle, &rtcTime, RTC_FORMAT_BCD);

  while (1)
  {

  }
}

static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  /* Enable Power Control clock */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /* Enable HSE Oscillator and activate PLL with HSE as source */
  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;
#if defined(USE_STM32469I_DISCO_REVA)
  RCC_OscInitStruct.PLL.PLLM = 25;
#else
  RCC_OscInitStruct.PLL.PLLM = 8;
#endif /* USE_STM32469I_DISCO_REVA */
  RCC_OscInitStruct.PLL.PLLN = 360;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  RCC_OscInitStruct.PLL.PLLR = 6;

  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /* Enable the OverDrive to reach the 180 Mhz Frequency */  
  if(HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    Error_Handler();
  }

  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;  
  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
static void Error_Handler(void)
{
  /* User may add here some code to deal with this error */
  while(1)
  {
  }
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

And it doesn't work. After some digging into lowest layer, I managed to find where it doesn't work. I just don't know why.

The HAL_RTC_Init() call returns a HAL_ERROR Status. This HAL_ERROR appears because the HAL_RTC_Init() calls RTC_EnterInitMode() and it returns a HAL_TIMEOUT Status because a condition is not achieved during the time expected. Here are the functions :

HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc)
{
  /* Check the RTC peripheral state */
  if(hrtc == NULL)
  {
     return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_RTC_HOUR_FORMAT(hrtc->Init.HourFormat));
  assert_param(IS_RTC_ASYNCH_PREDIV(hrtc->Init.AsynchPrediv));
  assert_param(IS_RTC_SYNCH_PREDIV(hrtc->Init.SynchPrediv));
  assert_param (IS_RTC_OUTPUT(hrtc->Init.OutPut));
  assert_param (IS_RTC_OUTPUT_POL(hrtc->Init.OutPutPolarity));
  assert_param(IS_RTC_OUTPUT_TYPE(hrtc->Init.OutPutType));

  if(hrtc->State == HAL_RTC_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hrtc->Lock = HAL_UNLOCKED;
    /* Initialize RTC MSP */
    HAL_RTC_MspInit(hrtc);
  }

  /* Set RTC state */  
  hrtc->State = HAL_RTC_STATE_BUSY;  

  /* Disable the write protection for RTC registers */
  __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);

  /* Set Initialization mode */
  if(RTC_EnterInitMode(hrtc) != HAL_OK)
  {
    /* Enable the write protection for RTC registers */
    __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); 
    /* Set RTC state */
    hrtc->State = HAL_RTC_STATE_ERROR;

    return HAL_ERROR;
  } 
  else
  { 
    /* Clear RTC_CR FMT, OSEL and POL Bits */
    hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL));
    /* Set RTC_CR register */
    hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity);

    /* Configure the RTC PRER */
    hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv);
    hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16U);

    /* Exit Initialization mode */
    hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; 

    hrtc->Instance->TAFCR &= (uint32_t)~RTC_TAFCR_ALARMOUTTYPE;
    hrtc->Instance->TAFCR |= (uint32_t)(hrtc->Init.OutPutType); 

    /* Enable the write protection for RTC registers */
    __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); 

    /* Set RTC state */
    hrtc->State = HAL_RTC_STATE_READY;

    return HAL_OK;
  }
}

and :

HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef* hrtc)
{
  uint32_t tickstart = 0U; 

  /* Check if the Initialization mode is set */
  if((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
  {
    /* Set the Initialization mode */
    hrtc->Instance->ISR = (uint32_t)RTC_INIT_MASK;

    /* Get tick */
    tickstart = HAL_GetTick();

    /* Wait till RTC is in INIT state and if Time out is reached exit */
    while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
    {
      if((HAL_GetTick() - tickstart ) > RTC_TIMEOUT_VALUE)
      {
        return HAL_TIMEOUT;
      } 
    }
  }

  return HAL_OK;  
}

So, if I investigated nicely, the issue is that the condition : hrtc->Instance->ISR & RTC_ISR_INITF == (uint32_t)RESET is true all the time (since the TIMEOUT condition is raised). The ting I don't understand is according to the function above (EnterInitMode), RTC_ISR_INITF and ISR variables seem to be clearly define and thus, the bitwise operation value is not 0 (RESET).

The "ISR" is defined in the function directly and is RTC_INIT_MASK (#define with 0xFFFFFFFF value in stm32f4xx_hal_rtc.h)

The "RTC_ISR_INITF" is a macro : (0x1U << RTC_ISR_INITF_Pos) where RTC_ISR_INITF_Pos is 6U (#define) defined in stm32f469xx.h

Am I wrong if I say that the "&" operation is not 0 ?

Do you have any idea why I have this TIMEOUT condition raised ?

Thanks in advance !

timer
stm32
real-time-clock
asked on Stack Overflow Apr 4, 2017 by vionyst • edited Jun 12, 2017 by BNT

1 Answer

7

I solved my problem after a good night. I forgot to initialize the LSE Clock in my SystemClock_Config() routine... I simply add the following code in SystemClock_Config().

RCC_OscInitTypeDef RCC_OscInitLSE;

RCC_OscInitLSE.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitLSE.LSEState = RCC_LSE_ON;

if(HAL_RCC_OscConfig(&RCC_OscInitLSE) != HAL_OK){
      Error_Handler();
}

I tested afterward with STM Studio to visualize the evolution of my variables. And it worked well (it didn't previously).

Sorry for the inconvenience.

answered on Stack Overflow Apr 5, 2017 by vionyst

User contributions licensed under CC BY-SA 3.0