cancel
Showing results for 
Search instead for 
Did you mean: 

Having trouble with Internal RTC backup registers with F413ZH controller

Abhishek Deouskar
Associate III

Hello,

I have a custom board with the F413ZH controller on it. For retaining RTC information after power loss, I have connected a 3.3V coin cell and a 32.768 khz crystal on LSE. However, I am facing issues with the Backup registers on the software side.

Please find my code and do help out. I may be missing something very vital and minor.

//My custom Lib for RTC
#define InternalRTCHandle	&hrtc
 
typedef enum{
	InternalRTC_OK			= 0x00,
	InternalRTC_TimeNotSet	= 0x01,
	InternalRTC_DateNotSet	= 0x02,
 
	InternalRTC_TimeNotOK	= 0x11,
	InternalRTC_DateNotOK	= 0x12
}InternalRTC_Status;
 
typedef struct{
	uint8_t seconds; /*!< Seconds parameter, from 00 to 59 */
	uint8_t minutes; /*!< Minutes parameter, from 00 to 59 */
	uint8_t hours;   /*!< Hours parameter, 24Hour mode, 00 to 23 */
	uint8_t day;     /*!< Day in a week, from 1 to 7 */
	uint8_t date;    /*!< Date in a month, 1 to 31 */
	uint8_t month;   /*!< Month in a year, 1 to 12 */
	uint8_t year;    /*!< Year parameter, 00 to 99, 00 is 2000 and 99 is 2099 */
}InternalRTC_DateTime;
 
InternalRTC_DateTime	ISetCurrentDateTime;
InternalRTC_DateTime	IGetCurrentDateTime;
 
InternalRTC_Status InternalRTC_SetDateTime(InternalRTC_DateTime *time)
{
	RTC_TimeTypeDef sTime = {0};
	RTC_DateTypeDef sDate = {0};
 
	sTime.Hours = time->hours;
	sTime.Minutes = time->minutes;
	sTime.Seconds = time->seconds;
	sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sTime.StoreOperation = RTC_STOREOPERATION_RESET;
	if (HAL_RTC_SetTime(InternalRTCHandle, &sTime, RTC_FORMAT_BIN) != HAL_OK)
	{
		return InternalRTC_TimeNotSet;
	}
	sDate.Month = time->month;
	sDate.Date = time->date;
	sDate.Year = time->year;
	sDate.WeekDay = time->day;
	if (HAL_RTC_SetDate(InternalRTCHandle, &sDate, RTC_FORMAT_BIN) != HAL_OK)
	{
		return InternalRTC_DateNotSet;
	}
 
	return InternalRTC_OK;
}
 
InternalRTC_Status InternalRTC_GetDateTime(InternalRTC_DateTime *time)
{
	RTC_DateTypeDef gDate;
	RTC_TimeTypeDef gTime;
 
	if((HAL_RTC_GetTime(InternalRTCHandle, &gTime, RTC_FORMAT_BIN)) != HAL_OK)
	{
		return InternalRTC_TimeNotOK;
	}
 
	time->seconds = gTime.Seconds;
	time->minutes = gTime.Minutes;
	time->hours = gTime.Hours;
	if((HAL_RTC_GetDate(InternalRTCHandle, &gDate, RTC_FORMAT_BIN)) != HAL_OK)
	{
		return InternalRTC_DateNotOK;
	}
 
	time->date = gDate.Date;
	time->month = gDate.Month;
	time->year = gDate.Year;
	time->day = gDate.WeekDay;
 
	return InternalRTC_OK;
}
 
uint32_t InternalRTC_ReadBackupRegs(uint32_t BackupRegTime, uint32_t BackupRegDate)
{
	uint32_t tempTime = 0;
	uint32_t tempDate = 0;
	uint32_t epochtime = 0;
	tempTime = HAL_RTCEx_BKUPRead(InternalRTCHandle, BackupRegTime);
	tempDate = HAL_RTCEx_BKUPRead(InternalRTCHandle, BackupRegDate);
	epochtime = (tempTime << 16) + (tempDate);
 
	return epochtime;
}
 
void InternalRTC_WriteBackupRegs(uint32_t BackupRegTime, uint32_t BackupRegDate, uint32_t data)
{
	HAL_RTCEx_BKUPWrite(InternalRTCHandle, BackupRegTime, (data >> 16));
	HAL_RTCEx_BKUPWrite(InternalRTCHandle, BackupRegDate, (uint16_t)(data));
}
 
uint32_t returnEpochTime (InternalRTC_DateTime *time1)
{
	struct tm ts;
 
	ts.tm_sec = time1->seconds;
	ts.tm_min = time1->minutes;
	ts.tm_hour = time1->hours;
 
	ts.tm_wday = time1->day - 1;
	ts.tm_mday = time1->date;
	ts.tm_mon = time1->month - 1;
	ts.tm_year = time1->year + 2000 - 1900;
	ts.tm_isdst = 0;
 
	return (mktime (&ts));
}
 
void returnTimeStructurefromEpochTime (uint32_t timefromBackupRegs, InternalRTC_DateTime *time1)
{
  time_t rawtime = timefromBackupRegs;
  struct tm ts;
 
  ts = *localtime (&rawtime);
 
  time1->seconds = ts.tm_sec;
  time1->minutes = ts.tm_min;
  time1->hours = ts.tm_hour;
 
  time1->day = ts.tm_wday;
  time1->date = ts.tm_mday;
  time1->month = ts.tm_mon + 1;
  time1->year = ts.tm_year + 1900 - 2000;
}
 

Here is what I wrote in main.c

#define SetDateTimeOnly		0
#define GetDateTimeOnly		1
 
  HAL_PWREx_EnableBkUpReg();		//Enables Backup Regulator
 
#if SetDateTimeOnly
  ISetCurrentDateTime.seconds = 40;
  ISetCurrentDateTime.minutes = 19;
  ISetCurrentDateTime.hours = 18;
 
  ISetCurrentDateTime.day = 03;
  ISetCurrentDateTime.date = 02;
  ISetCurrentDateTime.month = 10;
  ISetCurrentDateTime.year = 19;
 
  InternalRTC_SetDateTime(&ISetCurrentDateTime);
  uint32_t currentTime = returnEpochTime(&ISetCurrentDateTime);
  InternalRTC_WriteBackupRegs(RTC_BKP_DR1, RTC_BKP_DR2, currentTime);
 
#if IndependentDebugging_Main_C
  custom_printf("Set Time: %02u:%02u:%02u\t%02u/%02u/20%02u\tDay:%02u\r\n", ISetCurrentDateTime.hours, ISetCurrentDateTime.minutes, ISetCurrentDateTime.seconds, ISetCurrentDateTime.date, ISetCurrentDateTime.month, ISetCurrentDateTime.year, ISetCurrentDateTime.day);
  custom_printf("Set Epoch Time: In Dec:- %lu\tIn Hex: %lX\r\n", currentTime, currentTime);
#endif
#endif
 
#if GetDateTimeOnly
    uint32_t currentTime1 = InternalRTC_ReadBackupRegs(RTC_BKP_DR1, RTC_BKP_DR2);
 
#if IndependentDebugging_Main_C
    custom_Printf("Get Epoch Time: In Dec:- %lu\tIn Hex: %lX\r\n", currentTime1, currentTime1);
#endif
 
  returnTimeStructurefromEpochTime(currentTime1, &IGetCurrentDateTime);
  InternalRTC_SetDateTime(&IGetCurrentDateTime);
 
#if IndependentDebugging_Main_C
  custom_Printf("Get Parsed Time: %02u:%02u:%02u\t%02u/%02u/20%02u\tDay:%02u\r\n", IGetCurrentDateTime.hours, IGetCurrentDateTime.minutes, IGetCurrentDateTime.seconds, IGetCurrentDateTime.date, IGetCurrentDateTime.month, IGetCurrentDateTime.year, IGetCurrentDateTime.day);
#endif
#endif
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
#if GetDateTimeOnly
	  InternalRTC_GetDateTime(&IGetCurrentDateTime);
#if IndependentDebugging_Main_C
	  custom_Printf("%02u:%02u:%02u\t%02u/%02u/20%02u\tDay:%02u\r\n", IGetCurrentDateTime.hours, IGetCurrentDateTime.minutes,IGetCurrentDateTime.seconds, IGetCurrentDateTime.date, IGetCurrentDateTime.month, IGetCurrentDateTime.year, IGetCurrentDateTime.day);
#endif
	  uint32_t currentTime2 = returnEpochTime(&IGetCurrentDateTime);
	  InternalRTC_WriteBackupRegs(RTC_BKP_DR1, RTC_BKP_DR2, currentTime2);
	  HAL_Delay(1000);
#endif
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

If I do not switch off the power supply, the backup registers maintain their values. However, power up just resets them back to 0.

Any help is appreciated.

Thanking You.

10 REPLIES 10

I don't use Cube.

RTC maintains time when power is reset?

JW

Hi, Sorry for the extremely late reply. No. The RTC does not maintain time when power is reset. However, the Backup registers maintain their value.

Example: So, if I turned off the power off at say, 2:45:59 pm and then turn it back on 1 hour later, the values restart from 2:45:59 pm and not 3:45:59pm.

Looks as though I am not making proper LSE configs.

@Community member​ - Mostly even I don't use Cube for my main implementations. However, when I prototype, Cube is easiest and fastest.

Are you sure you run RTC from LSE? Check if it runs precisely (to distinguish LSE from LSI); check the RTC source in RTCSEL bits of RCC_BDCR.

JW

I checked and found that RCC_BDCR register return 0, i.e., No Clock source. But I have distinctly turned on the LSE here (Line 34 onwards):

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  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_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
}

Any reason for this?

> I checked and found that RCC_BDCR register return 0,

That would mean also LSE off, but also RTC not running (RTCEN=0).

Something is terribly wrong. Look at the RTC registers. If RTC is running, then you've read out RCC_BDCR incorrectly.

I don't use Cube, and won't comment on usage of Cube/HAL functions.

JW

I used a simple code to read the RTCSEL and the RTCEN, with multiple implementations that I could figure out:

uint8_t result1 = 0xFF;
  result1 = RCC->BDCR & RCC_BDCR_RTCSEL;
 
  uint8_t result2 = 0xFF;
  result2 = __HAL_RCC_GET_RTC_SOURCE();
 
  uint8_t result3 = 0xFF;
  result3 = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL);
 
  DebugPrint("result1 = %u\nresult2 = %u\nresult3 = %u\n", result1, result2, result3);
 
  uint8_t result4 = 0xFF;
  result4 = RCC->BDCR & RCC_BDCR_RTCEN;
 
  uint8_t result5 = 0xFF;
  result5 = READ_BIT(RCC->BDCR, RCC_BDCR_RTCEN);
 
  DebugPrint("result4 = %u\nresult5 = %u\n", result4, result5);
 
  while(1)
  {
 
  }

Results were as shown in image. Image shows RTCSEL and RTCEN = 0. However, when my controller is ON (and is connected to HSE), the RTC counts properly at 1Hz.

0690X00000AsXChQAN.png

This is a contradictory information. I don't know, what else could be done, then.

JW

Okay. Thank You. I will apprise you of any further developments. Help is much appreciated as it told me what to look for.

I realized that I was reading the registers wrong. The information was not contradictory. I was simply not reading the right bits. I wrote code for the proper bits for RTCSEL and RTCCEN and I got the appropriate values for LSE.

However, my original issue still remains unsolved.