cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_Delay() doesn't synch with RTC on STM32H7A3

magene
Senior II

I'm rewriting some of my old LL code to use HAL and having trouble getting the RTC to read time correctly. I have a simple test project where I'm calling HAL_RTC_GetTime() and HAL_RTC_GetDate() before and after a call to HAL_Delay() with the expectation that the difference in the 2 RTC calls will be something close the the HAL_Delay but that isn't happening.  I running on a custom SOM we've developed that uses a STM32H7A3LIH6Q with a 24 MHz HSE crystal and a 32.767 kHz LSE crystal. 

Here's my code:

 

 

#include "main.h"
#include "rtc.h"
#include "gpio.h"

void SystemClock_Config(void);

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

  MX_GPIO_Init();
  MX_RTC_Init();

  /* USER CODE BEGIN 2 */
	RTC_TimeTypeDef newTime1;
	RTC_DateTypeDef newDate1;
	RTC_TimeTypeDef newTime2;
  	RTC_DateTypeDef newDate2;

  	//Delay to get some non-zero value in newTime and newDate
  	HAL_Delay(4500);

  	//Initialize newTime1 and 2, newDate1 and 2
 	HAL_RTC_GetTime(&hrtc, &newTime2, RTC_FORMAT_BCD);
  	HAL_RTC_GetDate(&hrtc, &newDate2, RTC_FORMAT_BCD);
 	HAL_RTC_GetTime(&hrtc, &newTime1, RTC_FORMAT_BCD);
  	HAL_RTC_GetDate(&hrtc, &newDate1, RTC_FORMAT_BCD);

  	uint32_t delay = 1500;
  	for (int i = 0; i < 6; i++)
  	{
  		HAL_GPIO_TogglePin(LEDsom_GPIO_Port, LEDsom_Pin);
  		HAL_Delay(delay);
  	}

  	HAL_RTC_GetTime(&hrtc, &newTime2, RTC_FORMAT_BCD);
  	HAL_RTC_GetDate(&hrtc, &newDate2, RTC_FORMAT_BCD);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /*AXI clock gating */
  RCC->CKGAENR = 0xFFFFFFFF;

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Configure LSE Drive Capability
  */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 3;
  RCC_OscInitStruct.PLL.PLLN = 70;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

 

 

I would l have expected to see something like 4 in the newTime1.Seconds field.  The blinking LED for loop runs 6 times with a 1500 mSec delay so a total of 9 seconds which I've verified with a stop watch. So I would have expected to see something like 13 or 14 second in the New Time2.Seconds field. But here's what shows up in the Variables window.

magene_2-1720213155288.png

As a test, I modified the hrtc.Init.SynchPrediv from the default 255 to 127 and see newTime1.Seconds = 4 and newTime2.Seconds=19. But 255 is supposed to be the correct value for a 32.767 kHz LSE crystal according to the Reference Manual.

I started by creating a CubeMX project with nothing but the RTC enabled like this:

magene_0-1720212267571.png

The clock configuration is this:

magene_1-1720212325661.png

Any ideas on what I'm doing wrong and how to fix it will be greatly appreciated.

Thanks

 

 

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
magene
Senior II

I think I figured this out.  The RTC works fine when running off the LSI using the predividers recommended in AN4759.  And it works fine when running off the LSE if I set the RTC synchronous predivider to 80 instead of the 255 recommended in the AN.  The RTC timing was so far off, it didn't occur to me that my LSE could be that far off.  I'll figure out a way to check the LSE rate with a scope when I get a chance and hopefully be able to get it dialed in by adjusting the load capacitors. Using the RTC alarms is one way to get the RTC rate but it would be better if I can figure out a way to check closer to the LSE.

View solution in original post

2 REPLIES 2
magene
Senior II

Here's the CubeMX generated rtc.c file

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    rtc.c
  * @brief   This file provides code for the configuration
  *          of the RTC instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "rtc.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

RTC_HandleTypeDef hrtc;

/* RTC init function */
void MX_RTC_Init(void)
{

  /* USER CODE BEGIN RTC_Init 0 */

  /* USER CODE END RTC_Init 0 */

  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};

  /* USER CODE BEGIN RTC_Init 1 */

  /* USER CODE END RTC_Init 1 */

  /** Initialize RTC Only
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  //hrtc.Init.SynchPrediv = 255;
  hrtc.Init.SynchPrediv = 127;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */

  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date
  */
  sTime.Hours = 0x0;
  sTime.Minutes = 0x0;
  sTime.Seconds = 0x0;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_JANUARY;
  sDate.Date = 0x1;
  sDate.Year = 0x0;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN RTC_Init 2 */

  /* USER CODE END RTC_Init 2 */

}

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{

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

  /* USER CODE END RTC_MspInit 0 */

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
    PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }

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

  /* USER CODE END RTC_MspInit 1 */
  }
}

void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
{

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

  /* USER CODE END RTC_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_RTC_DISABLE();
  /* USER CODE BEGIN RTC_MspDeInit 1 */

  /* USER CODE END RTC_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */
magene
Senior II

I think I figured this out.  The RTC works fine when running off the LSI using the predividers recommended in AN4759.  And it works fine when running off the LSE if I set the RTC synchronous predivider to 80 instead of the 255 recommended in the AN.  The RTC timing was so far off, it didn't occur to me that my LSE could be that far off.  I'll figure out a way to check the LSE rate with a scope when I get a chance and hopefully be able to get it dialed in by adjusting the load capacitors. Using the RTC alarms is one way to get the RTC rate but it would be better if I can figure out a way to check closer to the LSE.