summaryrefslogtreecommitdiff
path: root/chip/stm32
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2020-11-27 18:31:43 +0100
committerCommit Bot <commit-bot@chromium.org>2020-12-02 09:39:09 +0000
commitaba388b6562aa2d37d98f4325cb8d2b06a0d8b26 (patch)
treea220a1d438976ec6cb90c1273a5e826388cd9e83 /chip/stm32
parent876bd4056b54df64ff834f1e5a17754fe65ee77d (diff)
downloadchrome-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.c10
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)