2019-10-03 12:47 AM
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.
2019-10-03 02:44 AM
I don't use Cube.
RTC maintains time when power is reset?
JW
2019-11-27 01:50 AM
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.
2019-11-27 03:43 AM
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
2019-11-27 05:38 AM
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?
2019-11-27 05:54 AM
> 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
2019-11-27 06:27 AM
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.
2019-11-27 07:45 AM
This is a contradictory information. I don't know, what else could be done, then.
JW
2019-11-27 11:23 PM
Okay. Thank You. I will apprise you of any further developments. Help is much appreciated as it told me what to look for.
2019-12-04 12:34 AM