Skip to main content
JSirk
Associate
October 17, 2018
Question

STM32F410 RTC fails on year

  • October 17, 2018
  • 12 replies
  • 3443 views

When writing to RTC and then reading back, my year is always off - writing 18 gives me back 21. Tried adding delays up to a second between instructions, no joy. Using Cube and MDK, RTC is running LSE 32768 and works fine otherwise. Both read and write depend on HAL libraries that I haven't touched.

typedef struct __TIME_INFO

{

   RTC_TimeTypeDef sTime;

   RTC_DateTypeDef sDate;

} TIME_INFO;

void rtc_updateRTCclock(TIME_INFO *t)

{

HAL_RTC_SetTime(&MAIN_RTC, &(t->sTime), RTC_FORMAT_BIN);

HAL_RTC_SetDate(&MAIN_RTC, &(t->sDate), RTC_FORMAT_BIN);

}

TIME_INFO rtc_getCurrentTime() {

   TIME_INFO t;

   HAL_RTC_GetTime(&MAIN_RTC, &(t.sTime), RTC_FORMAT_BIN);

   HAL_RTC_GetDate(&MAIN_RTC, &(t.sDate), RTC_FORMAT_BIN);

   return t;

}

This topic has been closed for replies.

12 replies

waclawek.jan
Super User
October 17, 2018

And what is in the RTC registers?

I don't Cube/HAL - do those functions properly unlock the backup domain and RTC before writing to registers, as outlined in RTC register write protection subchapter of RTC chapter of RM?

JW

JSirk
JSirkAuthor
Associate
October 17, 2018

Is there a handy instruction for reading them? #hwguy

JSirk
JSirkAuthor
Associate
October 17, 2018

I'd be tempted to say that the HAL library as supplied by ST should do data write and retrieval properly - I wouldn't have the competence to judge that. Also, given that everything else in both time and date is properly written and read back, I can't see how the write protection could be at fault.

I've banged my head to the wall for days with this now, after having banged my head last week on the Stop mode issue where one needs to call

HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFE);

twice for it to take effect.

waclawek.jan
Super User
October 17, 2018

> hwguy

That's no excuse. SW is the same as HW, you read the manuals thoroughly and then act accordingly.

Use the debugger to read out the registers. Or, in program, read RTC->TR and RTC->DR (in this order; read Reading the calendar subsection in RTC section of RM).

> one needs to call

> HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFE);

> twice for it to take effect.

Probably needs not, and there's some underlying reason why writing it twice appears to work.

JW

waclawek.jan
Super User
October 17, 2018

[deleted doubled post courtesy of updated force]

JSirk
JSirkAuthor
Associate
October 17, 2018

SW should be the same as HW in the sense that I wouldn't do a CPU with single transistors if I can get one all ready made. So using registers isn't my strong suite as I thought I'd get by with using ready made libraries that keep the required low level stuff out of view.

Managed to pull the DR value out, 0x1B7017. 1B is year in BCD format so that's 1 of tens and B=11 ones? Doesn't seem right. I'm guessing there's no internal checks on the RTC for proper values? Now to find out how that B gets there in the first place.

waclawek.jan
Super User
October 17, 2018

> I wouldn't do a CPU with single transistors if I can get one all ready made

SW has several orders of magnitude more degrees of freedom than HW so you can get ready-made "libraries", except that they inevitably cover only a fraction of possible usage modes. Also, with the processor you'd start with reading thoroughly its manual - did you do that with the "library" you've used? Please do so, you might perhaps start to see reasons to go for transistors.

> 1B is year in BCD format

Yes, incorrect as you've noted.

> Now to find out how that B gets there in the first place.

Most probably through

> HAL_RTC_SetDate(&MAIN_RTC, &(t->sDate), RTC_FORMAT_BIN);

and t->sDate not being in the format this function expects with RTC_FORMAT_BIN. My guess is that the struct was not entirely initialized. But by now you've figured, I guess.

JW

JSirk
JSirkAuthor
Associate
October 17, 2018

Don't get me started on the HAL User Manual... I've found out more about the usage and proper syntax of the libraries from Google than from that manual.

I finally found the problem and solution - while setting the year, month and date manually in main loop worked without a hitch, setting them after parsing them from an incoming string always failed. Turns out that the weekday parameter (that I don't even use but the RTC sure does) of my time structure defaults to something (likely 0) in main but when it's a temporary structure in a function, it can be anything and while the HAL_RTC_SetDate asserts all else, it doesn't assert the weekday so it can overlap into year. This should be fixed in stm32f4xx_hal_rtc.c in my opinion, but I'm not holding my breath.

Thanks Jan for the support!

waclawek.jan
Super User
October 17, 2018

> Don't get me started on the HAL User Manual...

As I've said, it's one of the reasons to go for the transistors.

> when it's a temporary structure in a function, it can be anything

Oh yes. The Cube manual ought to say that all used structs have to be initialized entirely. For some parts of the "library" there are initialization functions which do this (I don't see such for RTC_DateTypeDef though, but I'm not surprised - systematic approach is not Cube's forte). This is something which ought to be written as the first thing in Cube's manual - maybe it's there, I am not going to spoil my evening by looking at it.

> while the HAL_RTC_SetDate asserts all else, it doesn't assert the weekday

In [STM32Cube_FW_F4_V1.15.0]\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rtc.c (I know it's old but as I don't use it I don't care to update, and I don't believe this fell out in newer versions) in HAL_RTC_SetDate() at around its 16th line I see:

 assert_param(IS_RTC_WEEKDAY(sDate->WeekDay));

So I'd say you have the asserts switched off. Don't ask me how to check/turn on.

JW

Eliahu Aaron
Associate
January 17, 2019

I had the same problem. I found that the problem was not setting the WeekDay (when creating a struct RTC_DateTypeDef, the field WeekDay gets a random value). The value WeekDay must be set to a value between 0 to 7.

Explanation: The code for setting the date in function HAL_RTC_SetDate:

if (Format == RTC_FORMAT_BIN)
 
{
 
 assert_param(IS_RTC_YEAR(sDate->Year));
 
 assert_param(IS_RTC_MONTH(sDate->Month));
 
 assert_param(IS_RTC_DATE(sDate->Date));
 
 
 
 datetmpreg = (((uint32_t)RTC_ByteToBcd2(sDate->Year) << 16U) | \
 
 ((uint32_t)RTC_ByteToBcd2(sDate->Month) << 8U) | \
 
 ((uint32_t)RTC_ByteToBcd2(sDate->Date)) | \
 
 ((uint32_t)sDate->WeekDay << 13U));
 
}
 
else
 
{
 
 assert_param(IS_RTC_YEAR(RTC_Bcd2ToByte(sDate->Year)));
 
 assert_param(IS_RTC_MONTH(RTC_Bcd2ToByte(sDate->Month)));
 
 assert_param(IS_RTC_DATE(RTC_Bcd2ToByte(sDate->Date)));
 
 
 
 datetmpreg = ((((uint32_t)sDate->Year) << 16U) | \
 
 (((uint32_t)sDate->Month) << 8U) | \
 
 ((uint32_t)sDate->Date) | \
 
 (((uint32_t)sDate->WeekDay) << 13U));
 
}

  • Date occupies bits 0-7: two BCD digits.
  • Month occupies bits 8-12: two BCD digits but the left digit can only be 0 or 1 - 5 bits is enough.
  • WeekDay occupies bits 13-15. one BCD digit from 1 to 7 - 3 bits is enough.
  • Year occupies bits 16-24.

When WeekDay is greater than 7, it overlaps with the bits of Year and can change it.