From dcebc7d480c26db68d58a3c34ae1c910e9ef2c0b Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 19 Apr 2021 13:56:57 +0200 Subject: [PATCH 1/5] drivers/rtt_rtc: implement rtc_get_time_ms() RTC on RTT usually runs at a frequency greater than 1 Hz, so sub-second precision is available. Add a function to get the current RTC timestamp together with it's sub-second component. --- drivers/include/periph/rtc.h | 13 +++++++++++++ drivers/rtt_rtc/Makefile.features | 2 ++ drivers/rtt_rtc/rtt_rtc.c | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 drivers/rtt_rtc/Makefile.features diff --git a/drivers/include/periph/rtc.h b/drivers/include/periph/rtc.h index 9a424fecc7..0071711999 100644 --- a/drivers/include/periph/rtc.h +++ b/drivers/include/periph/rtc.h @@ -90,6 +90,19 @@ int rtc_set_time(struct tm *time); */ int rtc_get_time(struct tm *time); +/** + * @brief Get current RTC time with sub-second component. + * Requires the `periph_rtc_ms` feature. + * + * @param[out] time Pointer to the struct to write the time to. + * @param[out] ms Pointer to a variable to hold the microsecond + * component of the current RTC time. + * + * @return 0 for success + * @return -1 an error occurred + */ +int rtc_get_time_ms(struct tm *time, uint16_t *ms); + /** * @brief Set an alarm for RTC to the specified value. * diff --git a/drivers/rtt_rtc/Makefile.features b/drivers/rtt_rtc/Makefile.features new file mode 100644 index 0000000000..1ed82b05fe --- /dev/null +++ b/drivers/rtt_rtc/Makefile.features @@ -0,0 +1,2 @@ +FEATURES_PROVIDED += periph_rtc +FEATURES_PROVIDED += periph_rtc_ms diff --git a/drivers/rtt_rtc/rtt_rtc.c b/drivers/rtt_rtc/rtt_rtc.c index 878bc6ea94..2e16ac69c6 100644 --- a/drivers/rtt_rtc/rtt_rtc.c +++ b/drivers/rtt_rtc/rtt_rtc.c @@ -28,6 +28,7 @@ #include "periph/rtc.h" #include "periph/rtt.h" +#include "timex.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -40,6 +41,7 @@ #define TICKS(x) ( (x) * RTT_SECOND) #define SECONDS(x) (_RTT(x) / RTT_SECOND) +#define SUBSECONDS(x) (_RTT(x) % RTT_SECOND) /* Place counter in .noinit section if no backup RAM is available. This means the date is undefined at cold boot, but will likely still @@ -133,6 +135,22 @@ int rtc_set_time(struct tm *time) return 0; } +int rtc_get_time_ms(struct tm *time, uint16_t *ms) +{ + uint32_t prev = rtc_now; + + /* repeat calculation if an alarm triggered in between */ + do { + uint32_t now = rtt_get_counter(); + uint32_t tmp = _rtc_now(now); + + rtc_localtime(tmp, time); + *ms = (SUBSECONDS(now) * MS_PER_SEC) / RTT_SECOND; + } while (prev != rtc_now); + + return 0; +} + int rtc_get_time(struct tm *time) { uint32_t prev = rtc_now; From 84bb42ce1f265c6c9b65b714aea07f0c72e81790 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 19 Apr 2021 14:30:23 +0200 Subject: [PATCH 2/5] tests/periph_rtc: add rtc_get_time_ms() to test --- tests/periph_rtc/Makefile | 3 ++- tests/periph_rtc/main.c | 49 ++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/tests/periph_rtc/Makefile b/tests/periph_rtc/Makefile index e549720ff4..3d33287f19 100644 --- a/tests/periph_rtc/Makefile +++ b/tests/periph_rtc/Makefile @@ -1,6 +1,7 @@ include ../Makefile.tests_common -FEATURES_REQUIRED = periph_rtc +FEATURES_REQUIRED += periph_rtc +FEATURES_OPTIONAL += periph_rtc_ms DISABLE_MODULE += periph_init_rtc diff --git a/tests/periph_rtc/main.c b/tests/periph_rtc/main.c index 09c4c41999..db798a6fd0 100644 --- a/tests/periph_rtc/main.c +++ b/tests/periph_rtc/main.c @@ -47,6 +47,18 @@ static void print_time(const char *label, const struct tm *time) time->tm_sec); } +static void print_time_ms(const char *label, const struct tm *time, uint16_t ms) +{ + printf("%s %04d-%02d-%02d %02d:%02d:%02d.%03d\n", label, + time->tm_year + TM_YEAR_OFFSET, + time->tm_mon + 1, + time->tm_mday, + time->tm_hour, + time->tm_min, + time->tm_sec, + ms); +} + static void inc_secs(struct tm *time, unsigned val) { time->tm_sec += val; @@ -81,8 +93,14 @@ int main(void) rtc_set_time(&time); /* read RTC to confirm value */ - rtc_get_time(&time); - print_time("Clock value is now ", &time); + if (IS_USED(MODULE_PERIPH_RTC_MS)) { + uint16_t ms; + rtc_get_time_ms(&time, &ms); + print_time_ms("Clock value is now ", &time, ms); + } else { + rtc_get_time(&time); + print_time("Clock value is now ", &time); + } /* set initial alarm */ inc_secs(&time, PERIOD); @@ -95,17 +113,32 @@ int main(void) /* clear alarm */ rtc_clear_alarm(); - rtc_get_time(&time); - print_time(" Alarm cleared at ", &time); + if (IS_USED(MODULE_PERIPH_RTC_MS)) { + uint16_t ms; + rtc_get_time_ms(&time, &ms); + print_time_ms(" Alarm cleared at ", &time, ms); + } else { + rtc_get_time(&time); + print_time(" Alarm cleared at ", &time); + } /* verify alarm has been cleared */ xtimer_sleep(PERIOD); - rtc_get_time(&time); + + const char *message; if (mutex_trylock(&rtc_mtx)) { - print_time(" Error: Alarm at ", &time); + message = " Error: Alarm at "; + } else { + message = " No alarm at "; } - else { - print_time(" No alarm at ", &time); + + if (IS_USED(MODULE_PERIPH_RTC_MS)) { + uint16_t ms; + rtc_get_time_ms(&time, &ms); + print_time_ms(message, &time, ms); + } else { + rtc_get_time(&time); + print_time(message, &time); } /* set alarm */ From 0991c2884902af87ea0b9c7f238fae3270345108 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 3 May 2021 00:34:10 +0200 Subject: [PATCH 3/5] cpu/lpc23xx: implement rtc_get_time_ms() --- cpu/lpc23xx/Kconfig | 1 + cpu/lpc23xx/Makefile.features | 1 + cpu/lpc23xx/periph/rtc.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/cpu/lpc23xx/Kconfig b/cpu/lpc23xx/Kconfig index 53951c9a7b..c7eec23b92 100644 --- a/cpu/lpc23xx/Kconfig +++ b/cpu/lpc23xx/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_LPC23XX select HAS_PERIPH_GPIO select HAS_PERIPH_GPIO_IRQ select HAS_PERIPH_TIMER_PERIODIC + select HAS_PERIPH_RTC_MS ## CPU Models config CPU_MODEL_LPC2387 diff --git a/cpu/lpc23xx/Makefile.features b/cpu/lpc23xx/Makefile.features index 25463d61a0..c302107180 100644 --- a/cpu/lpc23xx/Makefile.features +++ b/cpu/lpc23xx/Makefile.features @@ -3,5 +3,6 @@ FEATURES_PROVIDED += backup_ram FEATURES_PROVIDED += periph_dac FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_timer_periodic +FEATURES_PROVIDED += periph_rtc_ms include $(RIOTCPU)/arm7_common/Makefile.features diff --git a/cpu/lpc23xx/periph/rtc.c b/cpu/lpc23xx/periph/rtc.c index 2680d1806a..475aba0aa7 100644 --- a/cpu/lpc23xx/periph/rtc.c +++ b/cpu/lpc23xx/periph/rtc.c @@ -28,6 +28,7 @@ #include "periph/rtc.h" #include "VIC.h" #include "lpc23xx.h" +#include "timex.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -110,6 +111,22 @@ int rtc_get_time(struct tm *localt) return 0; } +int rtc_get_time_ms(struct tm *time, uint16_t *ms) +{ + uint16_t ccr_before, ccr_after; + + /* loop in case of overflow */ + do { + ccr_before = RTC_CCR >> 1; + rtc_get_time(time); + ccr_after = RTC_CCR >> 1; + } while (ccr_before > ccr_after); + + /* CCR is 15-bit counter, increments second with each overflow */ + *ms = (ccr_after * MS_PER_SEC) >> 15; + + return 0; +} int rtc_set_alarm(struct tm *localt, rtc_alarm_cb_t cb, void *arg) { From 40d952bcebf175fab31f6287f9e37f21c91f46ac Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 3 May 2021 00:37:54 +0200 Subject: [PATCH 4/5] kconfig: define HAS_PERIPH_RTC_MS feature --- kconfigs/Kconfig.features | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index 99c394b361..4ea790c421 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -252,6 +252,11 @@ config HAS_PERIPH_RTC help Indicates that an RTC peripheral is present. +config HAS_PERIPH_RTC_MS + bool + help + Indicates that the RTC peripheral can provide sub-second timestamps. + config HAS_PERIPH_RTT bool help From 7c1b5630d2a77904a450c21a943de2a3a1135cd1 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 4 May 2021 17:27:20 +0200 Subject: [PATCH 5/5] cpu/atmega_common: RTC: implement rtc_get_time_ms() --- cpu/atmega_common/Kconfig | 1 + cpu/atmega_common/Makefile.features | 1 + cpu/atmega_common/periph/rtc.c | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/cpu/atmega_common/Kconfig b/cpu/atmega_common/Kconfig index 599b319719..0e1079c5dd 100644 --- a/cpu/atmega_common/Kconfig +++ b/cpu/atmega_common/Kconfig @@ -20,6 +20,7 @@ config CPU_COMMON_ATMEGA select HAS_PERIPH_GPIO select HAS_PERIPH_GPIO_IRQ select HAS_PERIPH_PM + select HAS_PERIPH_RTC_MS select HAS_PERIPH_RTT_SET_COUNTER select HAS_PERIPH_TIMER_PERIODIC select HAS_PERIPH_WDT diff --git a/cpu/atmega_common/Makefile.features b/cpu/atmega_common/Makefile.features index 7b58b012bd..12dc75ff88 100644 --- a/cpu/atmega_common/Makefile.features +++ b/cpu/atmega_common/Makefile.features @@ -10,6 +10,7 @@ FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_eeprom FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_pm +FEATURES_PROVIDED += periph_rtc_ms FEATURES_PROVIDED += periph_rtt_set_counter FEATURES_PROVIDED += periph_timer_periodic FEATURES_PROVIDED += periph_wdt diff --git a/cpu/atmega_common/periph/rtc.c b/cpu/atmega_common/periph/rtc.c index 08ad449461..ea80deb851 100644 --- a/cpu/atmega_common/periph/rtc.c +++ b/cpu/atmega_common/periph/rtc.c @@ -102,6 +102,28 @@ int rtc_get_time(struct tm *time) return 0; } +int rtc_get_time_ms(struct tm *time, uint16_t *ms) +{ + uint8_t cnt_before, cnt_after; + + /* loop in case of overflow */ + do { + cnt_before = TCNT2; + + /* prevent compiler from reordering memory access to tm_now, + * including moving it out of the loop + */ + __asm__ volatile ("" : : : "memory"); + *time = tm_now; + + cnt_after = TCNT2; + } while (cnt_before > cnt_after); + + *ms = (cnt_after * 1000UL) >> 8; + + return 0; +} + int rtc_get_alarm(struct tm *time) { *time = tm_alarm;