Skip to main content
Explorer
March 11, 2025
Question

STM32U5 - Real confusion about RTC and sub-seconds tracking. Trying to use it to set time from NTP packets.

  • March 11, 2025
  • 3 replies
  • 2232 views

Hi all,

I'd like to use the RTC as a keeper of real-world clock. It would get synchronized with a (S)NTP server once a day. The RTC would get queried multiple times a day for the current time. The main challenge is that I'd like the timestamps to have a resolution of about 1ms. This should be possible according to the manual, but I'm not sure how to utilize the HAL to do so (if it's even supported by the HAL). When reading some HAL functions, it's mentioned that HAL_RTC_SetTime doesn't set the sub-seconds register.

Is it correct to assume I'll need to use the low-level drivers to implement this functionality?

Thanks

 

    This topic has been closed for replies.

    3 replies

    Super User
    March 11, 2025

    The sub-seconds register is not directly writeable.

    After writing date/time, you can use the RTC->SHIFTR register to add/subtract fractions of a second from the current time. The function HAL_RTCEx_SetSynchroShift does this.

    No low level calls necessary.

    netheciteAuthor
    Explorer
    March 11, 2025

    Thank you, TDK, that is a relief to hear. I'll try it out.

    Another confusing thing with regards to RTC and sub-seconds is the relation between the synchronous predivider (PREDIV_S) and the update frequency of the RTC.

    By default, when:

     hrtc.Init.AsynchPrediv = 127;
     hrtc.Init.SynchPrediv = 255;

    Then if I set an initial time of 0:

     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();
     }

    And query the time every 5 seconds, I get the expected result of seeing the seconds counter increase by 5.

    while(1) {
     HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
     printf("%02d:%02d:%02d\r\n",sTime.Hours, sTime.Minutes, sTime.Seconds);
     HAL_Delay(5000);
    }

    However, according to the manual, the PREDIV_S value must be updated in order to control the precision of the sub-seconds register. So when I increased it to 16383 (to support a resolution of 60us, for example), I noticed that the seconds counter reported in my test above has incremented at a significantly lower rate.

    Is it possible to set PREDIV_S/A so that the counter keeps running as normal, but I can still do reads at sub-second resolution?

     

    Super User
    March 11, 2025

    The prescalers must be changed so that the CK_SPRE happens at 1 Hz.

    If you are using a 32.768 kHz clock, then you must have (PREDIV_A + 1) * (PREDIV_S + 1) = 32768. So increase one and decrease the other. PREDIV_S is not an independent knob to adjust precision.

     

    TDK_0-1741665114624.png

     

    netheciteAuthor
    Explorer
    March 11, 2025

    Thanks again for this information. Yes, I read that in the reference manual, however, it is still unclear to me how everything ties up together: fCK_SPRE, fCK_APRE, and how the RTC advances its internal hour/minute/seconds counters.

    Is there a configuration that would allow the RTC to advance the "seconds" register every 1 second, while still keeping the SSR register moving at a resolution that allows, say 0.25ms accuracy (PREDIV_S set to 4095)?

    Based on your comment, it looks like the answer is "no".

    My intended use case is to get NTP packets with 32 bits of unix time (number of seconds since 1970), and 32 bits of fraction of a second. I'm hoping to somehow store this in the RTC so that it can keep track of this with a desired sub-second resolution. All I need for the RTC is to produce a current timestamp when I ask for it, but it doesn't need to be in human-readable format.

    Perhaps the RTC isn't the right peripheral for this?

    Super User
    March 11, 2025

    > Is there a configuration that would allow the RTC to advance the "seconds" register every 1 second, while still keeping the SSR register moving at a resolution that allows, say 0.25ms accuracy (PREDIV_S set to 4095)?

    Well, from my post, I said you need to have (PREDIV_A + 1) * (PREDIV_S + 1) = 32768 if your clock is 32.768 kHz.

    If you want PREDIV_S = 4095, then let's do the math here:

    (PREDIV_A + 1) * (4095 + 1) = 32768

    PREDIV_A + 1 = 32768 / 4096 = 8

    PREDIV_A = 7

    So yes, you can have PREDIV_S = 4095 and PREDIV_A = 7.

    Super User
    March 13, 2025

    If you don't like the inherent mechanism built into the RTC hardware, one possible option is to leave RTC free running and have the difference stored e.g. in the backup registers, then apply the difference each time time is read out.

    You can also start a timer with time to the next seconds rollover, stop the RTC, set it with the next second, and then start it when the timer expires.

    You can also use the RTC only as a battery-backup of the real time, and upon read out real time, store it as a "local epoch", and start a timer. Then during runtime you wouldn't need to read RTC and do any conversion, just read the "local epoch" and add it to the timer's counter. This allows you to use the native RTC time correction, where the complexity of subseconds being above one second is hidden in the calculation of "local epoch" which is performed only once per reset.

    JW