diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2020-11-27 18:31:43 +0100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-12-02 09:39:09 +0000 |
commit | aba388b6562aa2d37d98f4325cb8d2b06a0d8b26 (patch) | |
tree | a220a1d438976ec6cb90c1273a5e826388cd9e83 /chip/stm32 | |
parent | 876bd4056b54df64ff834f1e5a17754fe65ee77d (diff) | |
download | chrome-ec-aba388b6562aa2d37d98f4325cb8d2b06a0d8b26.tar.gz |
stm32: fix RTC rounding error breaking alarms
On STM32F4, when converting micro-seconds to the RTC sub-second counter
value, the current computation in the us_to_rtcss() routine has a large
rounding error which can even led to generate a negative value.
When such a negative value is output and then programmed in the
(unsigned) RTC_ALRMASSR register used to set the alarm precise
sub-second timestamp, it might put a wrong value in the past.
As a consequence when the RTC alarm is used a wake-up mechanism for the
low power idle, it might never fired and trigger a watchdog reboot.
An example of bad values on a STM32F412 with the RTC driven by the
32-kHz LSI:
- RTC_PREDIV_A = 1
- RTC_FREQ = (STM32F4_LSI_CLOCK / (RTC_PREDIV_A + 1) = 16000 /* Hz */
- RTC_PREDIV_S = (RTC_FREQ - 1) = 15999
- US_PER_RTC_TICK = 1000000 / RTC_FREQ = 62 /* rounded from 62.5 */
When converting 996000 us,
us_to_rtcss(996000) = RTC_PREDIV_S - (us / US_PER_RTC_TICK)
= 15999 - (996000 / 62)
= -65
returned as a uint32_t as 0xfffffffb.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BUG=b:130561737
TEST=manual, with the STOP mode enabled, we no longer see watchdog
reboot due to the RTC alarm being set in the past and never firing.
TEST=manual, verify that the output of the 'gettime' console command is not
drifting compared to the wall clock when the low power idle using the
RTC time is used.
BRANCH=fpmcu-bloonchipper
Change-Id: I53869539828bed9a5900d29407b5feba140b8217
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2563684
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'chip/stm32')
-rw-r--r-- | chip/stm32/clock-stm32f4.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/chip/stm32/clock-stm32f4.c b/chip/stm32/clock-stm32f4.c index 51d6027ef6..3580b7a02a 100644 --- a/chip/stm32/clock-stm32f4.c +++ b/chip/stm32/clock-stm32f4.c @@ -337,16 +337,20 @@ void clock_enable_module(enum module_id module, int enable) #define RTC_FREQ (STM32F4_LSI_CLOCK / (RTC_PREDIV_A + 1)) /* Hz */ #endif #define RTC_PREDIV_S (RTC_FREQ - 1) -#define US_PER_RTC_TICK (1000000 / RTC_FREQ) +/* + * Scaling factor to ensure that the intermediate values computed from/to the + * RTC frequency are fitting in a 32-bit integer. + */ +#define SCALING 1000 int32_t rtcss_to_us(uint32_t rtcss) { - return ((RTC_PREDIV_S - rtcss) * US_PER_RTC_TICK); + return ((RTC_PREDIV_S - rtcss) * (SECOND/SCALING) / (RTC_FREQ/SCALING)); } uint32_t us_to_rtcss(int32_t us) { - return (RTC_PREDIV_S - (us / US_PER_RTC_TICK)); + return (RTC_PREDIV_S - (us * (RTC_FREQ/SCALING) / (SECOND/SCALING))); } void rtc_init(void) |