syscalls: fix wraparound of RTC time
This change removes the erroneous cast to uint32_t (which caused time to wrap around after 1 hour) and splits the multiplication into two terms to remove the wraparound after 13 days. Ref. https://esp32.com/viewtopic.php?f=13&t=1908
This commit is contained in:
parent
e7db29b2a8
commit
cc8af68244
1 changed files with 17 additions and 2 deletions
|
@ -46,8 +46,23 @@
|
||||||
#ifdef WITH_RTC
|
#ifdef WITH_RTC
|
||||||
static uint64_t get_rtc_time_us()
|
static uint64_t get_rtc_time_us()
|
||||||
{
|
{
|
||||||
uint64_t ticks = rtc_time_get();
|
const uint64_t ticks = rtc_time_get();
|
||||||
return (uint32_t) ((ticks * esp_clk_slowclk_cal_get()) >> RTC_CLK_CAL_FRACT);
|
const uint32_t cal = esp_clk_slowclk_cal_get();
|
||||||
|
/* RTC counter result is up to 2^48, calibration factor is up to 2^24,
|
||||||
|
* for a 32kHz clock. We need to calculate (assuming no overflow):
|
||||||
|
* (ticks * cal) >> RTC_CLK_CAL_FRACT
|
||||||
|
*
|
||||||
|
* An overflow in the (ticks * cal) multiplication would cause time to
|
||||||
|
* wrap around after approximately 13 days, which is probably not enough
|
||||||
|
* for some applications.
|
||||||
|
* Therefore multiplication is split into two terms, for the lower 32-bit
|
||||||
|
* and the upper 16-bit parts of "ticks", i.e.:
|
||||||
|
* ((ticks_low + 2^32 * ticks_high) * cal) >> RTC_CLK_CAL_FRACT
|
||||||
|
*/
|
||||||
|
const uint64_t ticks_low = ticks & UINT32_MAX;
|
||||||
|
const uint64_t ticks_high = ticks >> 32;
|
||||||
|
return ((ticks_low * cal) >> RTC_CLK_CAL_FRACT) +
|
||||||
|
((ticks_high * cal) << (32 - RTC_CLK_CAL_FRACT));
|
||||||
}
|
}
|
||||||
#endif // WITH_RTC
|
#endif // WITH_RTC
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue