Skip to content

Commit

Permalink
tests/periph_rtc: test sub-second precision
Browse files Browse the repository at this point in the history
Adapted from @benemorius PR RIOT-OS#10763.
Add mircosecond precision test to RTC.
Adapt automated python test to match test API changes.
Assert max of 100 ms  error.

This is needed to test that an RTC alarm fires at the desired time and not with an arbitrary offset up to +/-1 second.
It also tests that rtc_set_time() behaves equivalently correctly, which is what I needed to test when I wrote this.
  • Loading branch information
MrKevinWeiss authored and benpicco committed Feb 8, 2021
1 parent 317534f commit a59218a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
47 changes: 37 additions & 10 deletions tests/periph_rtc/main.c
Expand Up @@ -35,6 +35,8 @@
#define TM_YEAR_OFFSET (1900)

static unsigned cnt = 0;
static uint32_t start_usecs = 0;
static uint32_t alarm_expected_usecs = 0;

static void print_time(const char *label, const struct tm *time)
{
Expand All @@ -47,14 +49,20 @@ static void print_time(const char *label, const struct tm *time)
time->tm_sec);
}

static void inc_secs(struct tm *time, unsigned val)
static void cb(void *arg)
{
time->tm_sec += val;
mutex_unlock(arg);
}

static void cb(void *arg)
static void rtc_wait(unsigned secs)
{
mutex_unlock(arg);
struct tm time;
mutex_t rtc_mtx = MUTEX_INIT_LOCKED;

rtc_get_time(&time);
time.tm_sec += secs;
rtc_set_alarm(&time, cb, &rtc_mtx);
mutex_lock(&rtc_mtx);
}

int main(void)
Expand All @@ -81,11 +89,12 @@ int main(void)
rtc_set_time(&time);

/* read RTC to confirm value */
rtc_get_time(&time);
print_time("Clock value is now ", &time);
struct tm time_now;
rtc_get_time(&time_now);
print_time("Clock value is now ", &time_now);

/* set initial alarm */
inc_secs(&time, PERIOD);
time.tm_sec += PERIOD;
print_time(" Setting alarm to ", &time);
rtc_set_alarm(&time, cb, &rtc_mtx);

Expand All @@ -108,24 +117,42 @@ int main(void)
print_time(" No alarm at ", &time);
}

/* sync to start of second */
rtc_wait(1);

/* set alarm */
rtc_get_time(&time);
inc_secs(&time, PERIOD);
start_usecs = xtimer_now_usec();
alarm_expected_usecs = start_usecs + US_PER_SEC * PERIOD;
time.tm_sec += PERIOD;
rtc_set_alarm(&time, cb, &rtc_mtx);
print_time(" Setting alarm to ", &time);
puts("");

printf("[%" PRIu32 "] First alarm expected at %" PRIu32 " µs\n",
xtimer_now_usec(),
alarm_expected_usecs);

/* loop over a few alarm cycles */
while (1) {
mutex_lock(&rtc_mtx);
puts("Alarm!");

/* capture time before printf */
uint32_t now_usecs = xtimer_now_usec();
if (++cnt < REPEAT) {
struct tm time;
rtc_get_alarm(&time);
inc_secs(&time, PERIOD);
time.tm_sec += PERIOD;
rtc_set_alarm(&time, cb, &rtc_mtx);
}

printf("[%" PRIu32 "] Alarm! after %" PRIu32 " µs "
"(error %" PRId32 " µs)\n",
now_usecs,
now_usecs - start_usecs,
(int32_t)now_usecs - alarm_expected_usecs);

alarm_expected_usecs = now_usecs + US_PER_SEC * PERIOD;
}

return 0;
Expand Down
9 changes: 7 additions & 2 deletions tests/periph_rtc/tests/01-run.py
Expand Up @@ -10,10 +10,11 @@
import sys
from testrunner import run


BOARD = os.getenv('BOARD', 'native')
DATE_PATTERN = r'\d{4}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2}'

max_offset_us = 100000 # 100 ms


def testfunc(child):
child.expect(r'This test will display \'Alarm\!\' every 2 seconds '
Expand All @@ -38,7 +39,11 @@ def testfunc(child):

child.expect(r" Setting alarm to ({})".format(DATE_PATTERN))
for _ in range(alarm_count):
child.expect_exact('Alarm!')
child.expect(r'\[[0-9]+\] Alarm! after [0-9]+ µs \(error'
r' (\-)*([0-9]+) µs\)')
eus = int(child.match.group(2))
assert abs(eus) <= max_offset_us, \
"Error ({}us) out of range, alarm_count={}".format(eus, _)


if __name__ == "__main__":
Expand Down

0 comments on commit a59218a

Please sign in to comment.