mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-29 08:21:18 +01:00
cpu/esp32: fixes and cleanups of RTC timer
- Unecessary definitions are removed. - Since the 48-bit RTC hardware timer uses a RC oscillator as clock, it is pretty inaccurate and leads to a RTC time deviation of up to 3 seconds per minute. Therefore, a calibration during the boot time determines a correction factor for the 48-bit RTC hardware timer. Function _rtc_time_to_us uses now this correction factor and converts a raw 48-bit RTC time to a corrected time in microseconds. Thus, the 48-bit RTC timer becomes much more accurate, but it can't still reach the accuracy of the PLL driven 64-bit system timer. The Advantage of using RTC over 64-bit sydtem timer is that it also continues in deep sleep mode and after software reset. - If the 64-bit system timer is used to emulate the RTC timer, it uses the RTC hardware timer to continue its operation after software .
This commit is contained in:
parent
21b2c8d334
commit
25d04c4742
@ -23,8 +23,8 @@
|
||||
* If module esp_rtc_timer is enabled, the 48-bit RTC hardware timer is used
|
||||
* directly. Otherwise the PLL driven 64-bit microsecond system timer is used
|
||||
* to emulate a RTC timer (default). This emulated RTC timer results into much
|
||||
* better accuracy. The Advantage of using RTC hardware timer over sytem timer
|
||||
* is that it would also continue in deep sleep mode.
|
||||
* better accuracy. The Advantage of using RTC hardware timer over system timer
|
||||
* is that it would also continue in deep sleep mode and after software reset.
|
||||
*/
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
@ -43,26 +43,19 @@
|
||||
#include "soc/rtc_cntl_struct.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "syscalls.h"
|
||||
#include "timex.h"
|
||||
#include "xtensa/xtensa_api.h"
|
||||
|
||||
/* TODO move to TIMER_SYSTEM definition in periph_cpu.h */
|
||||
#define TIMER_SYSTEM_GROUP TIMERG0
|
||||
#define TIMER_SYSTEM_INT_MASK BIT(0)
|
||||
#define TIMER_SYSTEM_INT_SRC ETS_TG0_T0_LEVEL_INTR_SOURCE
|
||||
#define TIMER_SYSTEM_CLK_HZ (1000000UL)
|
||||
|
||||
#define RTC_CLK_CAL_FRACT 19 /* fractional bits of calibration value */
|
||||
|
||||
/* we can't include soc/rtc.h because of rtc_init declaration conflicts */
|
||||
extern uint32_t rtc_clk_slow_freq_get_hz(void);
|
||||
|
||||
#if RTC_TIMER_USED
|
||||
|
||||
#define RTC_TIMER_CLK_HZ rtc_clk_slow_freq_get_hz()
|
||||
|
||||
#else /* RTC_TIMER_USED */
|
||||
|
||||
#define RTC_TIMER_CLK_HZ TIMER_SYSTEM_CLK_HZ
|
||||
|
||||
#endif /* RTC_TIMER_USED */
|
||||
extern uint32_t esp_clk_slowclk_cal_get(void);
|
||||
|
||||
/* static variables */
|
||||
static rtc_alarm_cb_t _rtc_alarm_cb = NULL;
|
||||
@ -72,43 +65,38 @@ static time_t _sys_alarm_time = 0;
|
||||
#define RTC_BSS_ATTR __attribute__((section(".rtc.bss")))
|
||||
|
||||
/* save several time stamps */
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_init_us;
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_init;
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_set_us;
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_set;
|
||||
static time_t RTC_BSS_ATTR _sys_time_set;
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_init_us; /* RTC time on init in us */
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_init; /* RTC time on init in cycles */
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_set_us; /* RTC time on set in us */
|
||||
static uint64_t RTC_BSS_ATTR _rtc_time_set; /* RTC time on set in cycles */
|
||||
static uint64_t RTC_BSS_ATTR _sys_time_set_us; /* system time on set in us */
|
||||
static time_t RTC_BSS_ATTR _sys_time_set; /* system time on set in sec */
|
||||
static uint64_t RTC_BSS_ATTR _sys_time_off_us; /* system time offset in us */
|
||||
|
||||
/* forward declarations */
|
||||
static time_t _sys_get_time (void);
|
||||
static uint64_t _rtc_get_time_raw(void);
|
||||
static time_t _sys_get_time (void); /* system time in seconds */
|
||||
static uint64_t _rtc_get_time_raw(void); /* RTC time in cycles */
|
||||
static uint64_t _rtc_time_to_us(uint64_t raw); /* convert RTC cycles to us */
|
||||
static void IRAM_ATTR _rtc_timer_handler(void* arg);
|
||||
|
||||
void rtc_init(void)
|
||||
{
|
||||
uint64_t _rtc_time_us = _rtc_time_to_us(_rtc_get_time_raw());
|
||||
|
||||
if (_rtc_time_init == 0 && _rtc_time_init_us == 0) {
|
||||
/* only set it new, if it was not set before */
|
||||
_rtc_time_init = _rtc_get_time_raw();
|
||||
_rtc_time_init_us = _rtc_get_time_raw();
|
||||
_rtc_time_init_us = _rtc_time_us;
|
||||
_sys_time_off_us = 0;
|
||||
|
||||
DEBUG("%s saved rtc_init=%lld rtc_init_us=%lld\n",
|
||||
__func__, _rtc_time_init, _rtc_time_init_us);
|
||||
|
||||
}
|
||||
|
||||
#if RTC_TIMER_USED
|
||||
/* restore microsecond system timer from RTC timer */
|
||||
uint64_t _rtc_time_now = _rtc_get_time_raw();
|
||||
uint64_t _sys_time_now = (_rtc_time_now > UINT32_MAX) ?
|
||||
_rtc_time_now / RTC_TIMER_CLK_HZ * TIMER_SYSTEM_CLK_HZ :
|
||||
_rtc_time_now * TIMER_SYSTEM_CLK_HZ / RTC_TIMER_CLK_HZ;
|
||||
|
||||
/* restore system timer */
|
||||
TIMER_SYSTEM.load_high = (uint32_t)(_sys_time_now >> 32);
|
||||
TIMER_SYSTEM.load_low = (uint32_t)(_sys_time_now & 0xffffffff);
|
||||
TIMER_SYSTEM.reload = 0;
|
||||
|
||||
DEBUG("%s restored rtc_init=%lld rtc_init_us=%lld\n",
|
||||
__func__, _rtc_time_init, _rtc_time_init_us);
|
||||
#endif
|
||||
else {
|
||||
_sys_time_off_us = _rtc_time_us - _rtc_time_set_us;
|
||||
}
|
||||
_sys_time_set_us = 0;
|
||||
}
|
||||
|
||||
void rtc_poweron(void)
|
||||
@ -125,12 +113,15 @@ void rtc_poweroff(void)
|
||||
|
||||
int rtc_set_time(struct tm *ttime)
|
||||
{
|
||||
_rtc_time_set_us = system_get_time_64();
|
||||
_rtc_time_set = _rtc_get_time_raw();
|
||||
_sys_time_set = mktime (ttime);
|
||||
_rtc_time_set_us = _rtc_time_to_us(_rtc_time_set);
|
||||
|
||||
DEBUG("%s sys_time_set=%ld sys_time_us=%lld rtc_time_set=%lld\n",
|
||||
__func__, _sys_time_set, system_get_time_64(), _rtc_time_set);
|
||||
_sys_time_set = mktime(ttime);
|
||||
_sys_time_set_us = system_get_time_64();
|
||||
_sys_time_off_us = 0;
|
||||
|
||||
DEBUG("%s sys_time=%ld rtc_time=%lld rtc_time_us=%lld\n",
|
||||
__func__, _sys_time_set, _rtc_time_set, _rtc_time_set_us);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -139,8 +130,8 @@ int rtc_get_time(struct tm *ttime)
|
||||
{
|
||||
time_t _sys_time = _sys_get_time();
|
||||
|
||||
DEBUG("%s sys_time=%ld rtc_time=%lld\n", __func__,
|
||||
_sys_time, _rtc_get_time_raw());
|
||||
DEBUG("%s sys_time=%ld rtc_time=%lld rtc_time_us=%lld\n", __func__,
|
||||
_sys_time, _rtc_get_time_raw(), _rtc_time_to_us(_rtc_get_time_raw()));
|
||||
|
||||
struct tm* _time = localtime(&_sys_time);
|
||||
if (_time) {
|
||||
@ -183,7 +174,7 @@ int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
|
||||
|
||||
/* determine the offset of alarm time to current time in RTC time */
|
||||
uint64_t _rtc_time_alarm;
|
||||
_rtc_time_alarm = _rtc_time_set + _sys_time_offset * RTC_TIMER_CLK_HZ;
|
||||
_rtc_time_alarm = _rtc_time_set + _sys_time_offset * rtc_clk_slow_freq_get_hz();
|
||||
|
||||
DEBUG("%s sys=%d sys_alarm=%d rtc=%lld rtc_alarm=%lld\n", __func__,
|
||||
_sys_get_time(), _sys_time_offset, _rtc_get_time_raw(), _rtc_time_alarm);
|
||||
@ -210,27 +201,17 @@ int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
|
||||
|
||||
#else
|
||||
|
||||
/* determine the offset of alarm time to the RTC set time */
|
||||
uint64_t _rtc_time_alarm;
|
||||
/* determine the offset of alarm time to the RTC set time in us */
|
||||
uint64_t _sys_alarm_us;
|
||||
_sys_alarm_us = _sys_time_set_us - _sys_time_off_us + _sys_time_offset * US_PER_SEC;
|
||||
|
||||
#if RTC_TIMER_USED
|
||||
/* convert rtc_time_set to time in us taking care with big numbers */
|
||||
_rtc_time_alarm = _rtc_time_set_us + _sys_time_offset * TIMER_SYSTEM_CLK_HZ;
|
||||
|
||||
DEBUG("%s sys=%ld sys_alarm=%ld rtc_set_us=%lld rtc_us=%lld rtc_alarm_us=%lld\n", __func__,
|
||||
_sys_get_time(), _sys_time_offset,
|
||||
_rtc_time_set_us, system_get_time_64(), _rtc_time_alarm);
|
||||
#else
|
||||
_rtc_time_alarm = _rtc_time_set + _sys_time_offset * TIMER_SYSTEM_CLK_HZ;
|
||||
|
||||
DEBUG("%s sys=%ld sys_alarm=%ld rtc=%lld rtc_alarm=%lld\n", __func__,
|
||||
_sys_get_time(), _sys_time_offset, _rtc_get_time_raw(), _rtc_time_alarm);
|
||||
|
||||
#endif
|
||||
DEBUG("%s sys_time=%ld sys_time_offset=%ld "
|
||||
"sys_time_us=%lld sys_time_alarm_us=%lld\n", __func__,
|
||||
_sys_get_time(), _sys_time_offset, system_get_time_64(), _sys_alarm_us);
|
||||
|
||||
/* set the timer value */
|
||||
TIMER_SYSTEM.alarm_high = (uint32_t)(_rtc_time_alarm >> 32);
|
||||
TIMER_SYSTEM.alarm_low = (uint32_t)(_rtc_time_alarm & 0xffffffff);
|
||||
TIMER_SYSTEM.alarm_high = (uint32_t)(_sys_alarm_us >> 32);
|
||||
TIMER_SYSTEM.alarm_low = (uint32_t)(_sys_alarm_us & 0xffffffff);
|
||||
|
||||
/* clear the bit in status and set the bit in interrupt enable */
|
||||
TIMER_SYSTEM_GROUP.int_clr_timers.val |= TIMER_SYSTEM_INT_MASK;
|
||||
@ -288,10 +269,10 @@ void rtc_clear_alarm(void)
|
||||
static time_t _sys_get_time (void)
|
||||
{
|
||||
#if MODULE_ESP_RTC_TIMER
|
||||
return _sys_time_set +
|
||||
return _sys_time_set +
|
||||
(_rtc_time_to_us(_rtc_get_time_raw() - _rtc_time_set) / US_PER_SEC);
|
||||
#else
|
||||
return _sys_time_set +
|
||||
return _sys_time_set +
|
||||
((_sys_time_off_us + system_get_time_64() - _sys_time_set_us) / US_PER_SEC);
|
||||
#endif
|
||||
}
|
||||
@ -307,12 +288,13 @@ static uint64_t _rtc_get_time_raw(void)
|
||||
rtc_time = RTCCNTL.time0;
|
||||
rtc_time += ((uint64_t)RTCCNTL.time1.val) << 32;
|
||||
return rtc_time;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
return system_get_time_64();
|
||||
|
||||
#endif
|
||||
static uint64_t _rtc_time_to_us(uint64_t raw)
|
||||
{
|
||||
const uint32_t cal = esp_clk_slowclk_cal_get();
|
||||
return ((((raw >> 32) * cal) << (32 - RTC_CLK_CAL_FRACT)) + /* high part */
|
||||
(((raw & 0xffffffff) * cal) >> RTC_CLK_CAL_FRACT)); /* low part */
|
||||
}
|
||||
|
||||
static void IRAM_ATTR _rtc_timer_handler(void* arg)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user