cancel
Showing results for 
Search instead for 
Did you mean: 

The time is: 33:55!

HTD
Senior III

I think it's related to my previous question:

https://community.st.com/s/question/0D53W00001sGksoSAC/is-it-possible-rtc-on-stm32h7-loses-1-second-on-each-power-cycle

I applied a workaround by practically removing all MX_RTC_Init().

It seems to work, however today my device showed 33:55 at 10:55. Why? It seems like after 23:59 the clock set to 24:00. To 25:00 one hour later.

Is this behavior related to initialization? I'm tempted to just check the TR for values over 23 and subtract 23 when initializing. It would obviously fix the issue, but it seems a little silly 😉

15 REPLIES 15

Read out and check content of RTC registers.

This is usually symptom of errorneously set 12/24 flag, usually due to using uninitialzed initialization struct in Cube. It's a recurring theme here.

JW

Yes, it started to occur since I disabled RTC_Init(). But now I have problem - when the RTC_Init() sets the control register (CR), I lose up to one second on each restart.

It's weird, since RTC_Init() doesn't touch the DR register.

Anyway, what I still need now is RTC that keeps time without ANY extra changes like resetting neither the seconds nor hours. Is it possible and how to enable this advanced feature? 😉

Which part of the RTC_Init() resets the fractions of seconds? I looked at the code and I can't figure it out. I see where the time format is set, along with some other bits. It seems like I could just leave the code as it is, but then the fractions of seconds keep being reset.

Or perhaps BCD(HEX) vs Decimal

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

> Yes, it started to occur since I disabled RTC_Init().

That's not "yes", it has nothing to do with RTC_Init(). You are using an unitialized struct (okay maybe I should not call it init struct, but generally any struct used as parameter when calling cube/hal functions) when calling set time function. I gave above a link to text explining that.

> Which part of the RTC_Init() resets the fractions of seconds?

https://community.st.com/s/question/0D53W00001sGksoSAC/is-it-possible-rtc-on-stm32h7-loses-1-second-on-each-power-cycle and the link I gave you there explains the mechanism (using INIT clears the subseconds).

Read the RTC chapter in manual.

JW

I read it again several times, but I'm not sure if I understood this right this time:

According to the linked article, entering the INIT mode of RTC, that MX_RTC_Init() does just resets the fraction of the seconds indirectly, by resetting the clock divider, right?

The partial solution is just not call MX_RTC_Init() when the time was already set. Right?

However, when I power cycle the device, I get random 23h error. Random means sometimes I power cycle the device and it's OK, sometimes it's not OK. It's always 23h either added or subtracted from the correct time, or zero, sometimes nothing happens with the time.

As you've said: it has nothing to do RTC_Init(), so - a set time function.

The problem with this is HAL_RTC_SetTime() is not called at all on power cycle or reset.

I only call HAL_RTC_GetTime(). I'd suspect it requires the initialized RTC_InitTypeDef struct to work properly. Am I heading in the right direction with this? Or... I reset the time manually from the device's GUI after disabling the init function, so it stored the time in wrong format. It could happen.

If so, the full working solution would be to properly initialize the structure without touching the Instance property of htrc, right?

But the HAL_RTC_Init() doesn't do anything else. It takes init struct already initialized.

It just writes RTC registers, that leads to that fraction of seconds loss.

Here's the relevant main() fragment:

  /** Initialize RTC Only
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  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();
  }

It is executed on every start, so there's no chance the Init structure is uninitialized. All my code that uses the RTC uses HAL functions that refer to the initialized hrtc structure.

The hrtc.Init.HourFormat is always set to RTC_HOURFORMAT_24.

> According to the linked article, entering the INIT mode of RTC, that MX_RTC_Init() does just resets the fraction of the seconds indirectly, by resetting the clock divider, right?

Not by resetting the clock divider, but the RTC_SSR register is zeroed when RTC_ISR.INIT is set i.e. the initialization mode is entered (or maybe when it's exit - the effect is the same). I wanted to RTFM you on this, but can't find this information in RM and don't remember where do I get it from - maybe some other RM, maybe some appnote, maybe just experimentation.

> However, when I power cycle the device, I get random 23h error.

Read out and check/post RTC registers content, before and after the power cycle.

> The problem with this is HAL_RTC_SetTime() is not called at all on power cycle or reset.

Whenever you called it, by failing to fill in all fields in struct used to call it you inadvertently set the 12/24 bit in TR. Or maybe it's something else. Read out and check RTC registers content.

In the long run, the best way is to avoid using Cube/HAL entirely, and write your own functions. In that way you don't have to deal with whatever idiosyncracies Cube/HAL throws at you.

JW

Thanks, I'll make my own RTC_SetTime() (-like) function, setting all registers manually. I assumed HAL function does that, but well, if it did, it would probably work properly then.

> I'll make my own RTC_SetTime() (-like) function

I probably messed it up and it's not the "set time" function but maybe the "initialize rtc" function. I don't know and I don't care. This is because I deeply don't care about Cube and its users, just have seen this problem many times here and it was usually consequence of not setting some field in the struct - whether at initialization or time setting.

Cube is not broken per se (mostly, sometimes it is but it's relatively rare), but its usage has certain rules and you have to obey them. And these rules are not written down, they are mostly "enforced" by generating code after clicking in CubeMX and by relying on "intuitive naming" and such.

One such rule in particular is, that structs in Cube calls have to be filled entirely or zeroed explicitly. The fields of structs used in Cube calls are often indiscriminately ORed together and result stored to registers with multiple bits and fields. A field in the struct you don't even have heard of (unless looked up the definition of said struct and studied it meticulously), if uninitialized, may contain a random (not always truly random, but depending on previous run of the program, and this is part of the gotcha) value, which when ORed together with other fields, may result in changing surprising bits/bitfields in the target register.

Or maybe I'm wrong (I often am) and the reason for problems you see is something else. 

This is why the first thing to do, always, when the hardware behaves weirdly, to read out and check/post content of the said hardware registers. That usually reflects the truth, because the hardware does not care about you using Cube, any IDE, compiler, library or whatever, hardware works out of the registers. And yes, that means that you MUST read the manual Cube promised you won't need to, originally.

But again, Cube is not dumb (i.e. its authors are not dumb, even if that's the common assertion when one stumbles upon problems like these). Those functions are written so, that the fields are (mostly) checked at the entry for sanity, but as those checks are runtime and relatively expensive, they are conditional. FULL ASSERT or something, again, I don't use don't care. Would you use that, you would catch your error when it happens.

By writing your own code you are going to fight the intricacies of the hardware, but you can always refer directly to the RM and ask meaningful questions (i.e. other than "slapped Cube on it and it ain't work) here, and once you manage that, you will be freed from the - quite different - intricacies of the intermediate layer Cube presents.

I believe, I've written all this in other words in the texts I linked to. I write those texts exactly in order to spare time not needing to rewrite it again and again, when users here report similar problems again and again. Well, this time this did not work, for whatever reason.

JW

https://github.com/STMicroelectronics/STM32CubeH7/blob/4cb7c570fa5f2a362193d713a70b43ab02c68197/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rtc.c#L907

 hrtc->Instance->CR |= (uint32_t)(sTime->DayLightSaving | sTime->StoreOperation);

 and the preceding

/* Check the parameters */
  assert_param(IS_RTC_FORMAT(Format));
  assert_param(IS_RTC_DAYLIGHT_SAVING(sTime->DayLightSaving));
  assert_param(IS_RTC_STORE_OPERATION(sTime->StoreOperation));

 is what I meant by "uninitialized struct field may cause havoc", and "FULL ASSERT something something".

JW