diff --git a/tests/periph_timer_short_relative_set/Makefile b/tests/periph_timer_short_relative_set/Makefile new file mode 100644 index 0000000000..6978deae0d --- /dev/null +++ b/tests/periph_timer_short_relative_set/Makefile @@ -0,0 +1,17 @@ +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_timer + +USEMODULE += core_thread_flags + +# optionally configure timer under test. Defaults to xtimer config. +# TEST_TIMER_DEV takes a 0-based index to the periph_timer instance defined in +# the board's periph_conf.h. TEST_TIMER_FREQ as an integer number which will +# be used as "freq" parameter in the timer_init() call. +# Note: not all implementations support arbitrary frequencies. +#CFLAGS += -DTEST_TIMER_DEV=foo -DTEST_TIMER_FREQ=bar + +# this test currently fails all CI boards and native +TEST_ON_CI_BLACKLIST += all + +include $(RIOTBASE)/Makefile.include diff --git a/tests/periph_timer_short_relative_set/README.md b/tests/periph_timer_short_relative_set/README.md new file mode 100644 index 0000000000..96080af99b --- /dev/null +++ b/tests/periph_timer_short_relative_set/README.md @@ -0,0 +1,32 @@ +# Periph Timer Test for short timer_set() values + +## About + +This test exposes if timer_set() with very low values (down to zero) underflows. +For each value from 100 to 0, it'll try to set a timer with that length. +In human terms, that should trigger instantly (It depends on TEST_TIMER_FREQ. +The default configuration is 1MHz. Some boards configure 32768kHz, which is the +slowest configuration currently. So each line should trigger after at most +31us.). + +See this example of a timer_set() implementation: + + int timer_set(tim_t dev, int channel, unsigned int timeout) + { + return timer_set_absolute(dev, channel, timer_read(dev) + timeout); + } + +This will probably underflow if "timeout" is 0, or if an ISR interrupts +somewhere between the read and the timerSet_absolute() call. +Depending on the used frequency of the underlying timer and the time it +requires for the involved function calls, reading the timer register, doing the +addition and writing back to the register, this will also fail for higher +timeouts. + +For example, as of this writing (30-Oct-19), samr21-xpro fails for values below +8, nrf52dk for values below 2. + +## Expected Result + +After 100 "interval N ok" messages the test should print "TEST SUCCEEDED". +On failure, the test will print "TEST FAILED". diff --git a/tests/periph_timer_short_relative_set/main.c b/tests/periph_timer_short_relative_set/main.c new file mode 100644 index 0000000000..a45d413b93 --- /dev/null +++ b/tests/periph_timer_short_relative_set/main.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Peripheral timer test application + * + * @author Kaspar Schleiser + * + * @} + */ + +#include +#include +#include + +#include "board.h" +#include "thread.h" +#include "thread_flags.h" + +#include "periph/timer.h" + +#ifndef TEST_TIMER_DEV +# include "xtimer.h" +# define TEST_TIMER_DEV XTIMER_DEV +# define TEST_TIMER_FREQ XTIMER_HZ +#else +# ifndef TEST_TIMER_FREQ +# define TEST_TIMER_FREQ (1000000LU) +# endif +#endif + +#ifndef TEST_MAX_DIFF +#define TEST_MAX_DIFF (1000LU) +#endif + +static void cb(void *arg, int chan) +{ + (void)chan; + thread_flags_set(arg, 1); +} + +int main(void) +{ + puts("\nTest for peripheral TIMER short timer_set()\n"); + + printf("This test tries timer_set() with decreasing intervals down to 0.\n" + "You should see lines like 'interval ok', followed by a success" + " message.\n" + "On failure, this test prints an error message.\n\n"); + + printf("testing periph_timer %u, freq %lu\n", TEST_TIMER_DEV, TEST_TIMER_FREQ); + timer_init(TEST_TIMER_DEV, TEST_TIMER_FREQ, cb, (thread_t *)sched_active_thread); + + uint32_t interval = 100; + while (interval--) { + uint32_t before = timer_read(TEST_TIMER_DEV); + timer_set(TEST_TIMER_DEV, 0, interval); + while(!thread_flags_clear(1)) { + uint32_t diff = timer_read(TEST_TIMER_DEV) - before; + if (diff > TEST_MAX_DIFF) { + printf("ERROR: too long delay, aborted after %" PRIu32 + " (TEST_MAX_DIFF=%lu)\n" + "TEST FAILED\n", + diff, TEST_MAX_DIFF); + while(1) {} + } + } + printf("interval %" PRIu32 " ok\n", interval); + } + + puts("\nTEST SUCCEEDED"); + + return 0; +} diff --git a/tests/periph_timer_short_relative_set/tests/01-run.py b/tests/periph_timer_short_relative_set/tests/01-run.py new file mode 100755 index 0000000000..1cb186eeb2 --- /dev/null +++ b/tests/periph_timer_short_relative_set/tests/01-run.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2019 Kaspar Schleiser +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact('TEST SUCCEEDED') + + +if __name__ == "__main__": + sys.exit(run(testfunc))