-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests/xtimer_configuration: Testing parameter
- Loading branch information
Showing
4 changed files
with
357 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
include ../Makefile.tests_common | ||
|
||
USEMODULE += xtimer | ||
|
||
# Port and pin configuration for probing with oscilloscope | ||
# Port number should be found in port enum e.g in cpu/include/periph_cpu.h | ||
FEATURES_REQUIRED += periph_gpio | ||
CFLAGS += -DSLEEP_PIN=6 | ||
CFLAGS += -DSLEEP_PORT=PORT_F | ||
|
||
CFLAGS += -DDEBUG_TIMER_PORT=PORTF | ||
CFLAGS += -DDEBUG_TIMER_DDR=DDRF | ||
CFLAGS += -DDEBUG_TIMER_PIN=PORTF4 | ||
|
||
include $(RIOTBASE)/Makefile.include | ||
|
||
test: | ||
./tests/01-run.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# xtimer_configuration test application | ||
|
||
This test tests `_xtimer_tsleep32()` and `xtimer_periodic_wakeup` against the | ||
timings of of the xtimer. | ||
And agains the timings of the external host (PC). | ||
|
||
This test can be used to adjust `XTIMER_SHOOT_OVERHEAD`, `XTIMER_OVERHEAD`, | ||
`XTIMER_BACKOFF` and `XTIMER_ISR_BACKOFF`. | ||
This is to ensure that the xtimer interrupt is only as long as neccessary. | ||
|
||
## Usage | ||
``` | ||
make BOARD=<Board Name> flash test | ||
``` | ||
|
||
## Find right values | ||
|
||
1. Configure parameter in board.h as follow: | ||
`XTIMER_ISR_BACKOFF` has to be twice `XTIMER_OVERHEAD` | ||
``` | ||
#define XTIMER_BACKOFF (100) | ||
#define XTIMER_ISR_BACKOFF (100) | ||
#define XTIMER_BACKOFF_OVERHEAD (1) | ||
#define XTIMER_OVERHEAD (50) | ||
#define XTIMER_SHOOT_OVERHEAD (0) | ||
``` | ||
|
||
run the test. | ||
If the output is as follows | ||
``` | ||
xxxx-xx-xx xx:xx:xx,xxx - INFO # 240876 243436 slept for 2560 ticks (20480 us) expected 2560 ticks, diff 27 ticks | ||
Increase value for XTIMER_SHOOT_OVERHEAD or XTIMER_OVERHEAD 27 | ||
... | ||
xxxx-xx-xx xx:xx:xx,xxx - INFO # 266798 266845 slept for 47 ticks (376 us) expected 47 ticks, diff 14 ticks | ||
Increase value for XTIMER_BACKOFF_OVERHEAD 14 | ||
``` | ||
|
||
Add the new value for `XTIMER_SHOOT_OVERHEAD` and `XTIMER_BACKOFF_OVERHEAD` to the board.h and set `XTIMER_OVERHEAD` to zero. | ||
|
||
``` | ||
#define XTIMER_BACKOFF (100) | ||
#define XTIMER_ISR_BACKOFF (100) | ||
#define XTIMER_BACKOFF_OVERHEAD (14) | ||
#define XTIMER_OVERHEAD (0) | ||
#define XTIMER_SHOOT_OVERHEAD (27) | ||
``` | ||
|
||
2. run test again | ||
|
||
Set `XTIMER_OVERHEAD` to new value. | ||
|
||
If the output is as follows | ||
|
||
``` | ||
xxxx-xx-xx xx:xx:xx,xxx - INFO # 240876 243436 slept for 2560 ticks (20480 us) expected 2560 ticks, diff 33 ticks | ||
Increase value for XTIMER_SHOOT_OVERHEAD or XTIMER_OVERHEAD 33 | ||
``` | ||
Set 33 as value for `XTIMER_OVERHEAD` and `XTIMER_BACKOFF` two times this value. | ||
Also set `XTIMER_ISR_BACKOFF` to `XTIMER_BACKOFF_OVERHEAD`. | ||
|
||
``` | ||
#define XTIMER_BACKOFF (66) | ||
#define XTIMER_ISR_BACKOFF (14) | ||
#define XTIMER_BACKOFF_OVERHEAD (14) | ||
#define XTIMER_OVERHEAD (33) | ||
#define XTIMER_SHOOT_OVERHEAD (27) | ||
``` | ||
|
||
3. Run the test again and check if there are values which are far off. | ||
|
||
now run `tests/xtimer_usleep_short` and `tests/xtimer_usleep`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* | ||
* Copyright (C) 2017 Inria | ||
* 2017 Freie Universität Berlin | ||
* | ||
* 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 xtimer_usleep test application | ||
* | ||
* @author Francisco Acosta <francisco.acosta@inria.fr> | ||
* @author Martine Lenders <m.lenders@fu-berlin.de> | ||
* @} | ||
*/ | ||
|
||
#include <inttypes.h> | ||
#include <stdio.h> | ||
|
||
#include "xtimer.h" | ||
#include "timex.h" | ||
#include "thread.h" | ||
|
||
#include "Board.h" | ||
|
||
/* | ||
* To use a pin to probe the sleep times enable the gpio module and define | ||
* respective DSLEEP_PIN and DSLEEP_PORT. | ||
* | ||
* Port number should be found in port enum e.g in cpu/include/periph_cpu.h | ||
* | ||
* FEATURES_REQUIRED += periph_gpio | ||
* CFLAGS += -DSLEEP_PIN=6 | ||
* CFLAGS += -DSLEEP_PORT=PORT_F | ||
* */ | ||
#if defined(SLEEP_PORT) | ||
#include "board.h" | ||
#include "periph/gpio.h" | ||
#endif | ||
|
||
#define RUNS (3U) | ||
#define SLEEP_TIMES_NUMOF (sizeof(sleep_times) / sizeof(sleep_times[0])) | ||
|
||
#define CLOCK_CICLE ((1ul) << XTIMER_WIDTH) | ||
static const uint32_t sleep_times[] = { | ||
XTIMER_BACKOFF - 1, /* spin adjust XTIMER_BACKOFF_OVERHEAD*/ | ||
XTIMER_BACKOFF + 1, /* no backoff test */ | ||
XTIMER_PERIODIC_SPIN, /* for sure no backoff */ | ||
CLOCK_CICLE, /* shoot with interrupt adjust*/ | ||
1000, | ||
2345, | ||
50000, | ||
100000, | ||
123456, | ||
}; | ||
|
||
uint32_t start_kept[5 * SLEEP_TIMES_NUMOF]; | ||
uint32_t test_times[5 * SLEEP_TIMES_NUMOF]; | ||
volatile uint32_t end_times[SLEEP_TIMES_NUMOF]; | ||
|
||
static char stack[THREAD_STACKSIZE_MAIN]; | ||
static void *_thread(void *arg) | ||
{ | ||
(void)arg; | ||
uint8_t i = 0; | ||
|
||
puts("thread(): waiting going to sleep!"); | ||
|
||
while (1) { | ||
thread_sleep(); | ||
end_times[i++] = _xtimer_now(); | ||
} | ||
return NULL; | ||
} | ||
|
||
int main(void) | ||
{ | ||
uint32_t start_test, testtime; | ||
|
||
printf("Running test %u times with %u distinct sleep times\n", RUNS, | ||
(unsigned)SLEEP_TIMES_NUMOF); | ||
puts("Please hit any key and then ENTER to continue"); | ||
getchar(); | ||
start_test = xtimer_now_usec(); | ||
|
||
/* Testing Periodic with fixed time | ||
* Periodic wakeup has the fastest return time as the absolute value is set | ||
* as timestamp. | ||
*/ | ||
uint32_t periode, periode_ticks; | ||
xtimer_ticks32_t start_periode; | ||
|
||
/* Testing normal usage relativ timestamp*/ | ||
periode_ticks = 5 * XTIMER_PERIODIC_RELATIVE; | ||
periode = _xtimer_usec_from_ticks(periode_ticks); | ||
|
||
start_periode = xtimer_now(); | ||
for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) { | ||
start_kept[n] = start_periode.ticks32; | ||
xtimer_periodic_wakeup(&start_periode, periode); | ||
test_times[n] = _xtimer_now(); | ||
} | ||
|
||
for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) { | ||
uint32_t diff = test_times[n] - start_kept[n]; | ||
printf("%" PRIu32 " %" PRIu32 " slept for %" PRIu32 " ticks (%" PRIu32 | ||
" us) expected %" PRIu32 " ticks, diff %" PRIu32 " ticks\n", | ||
start_kept[n], test_times[n], diff, _xtimer_usec_from_ticks(diff), | ||
periode_ticks, diff - periode_ticks); | ||
} | ||
|
||
/* Testing ticks */ | ||
/* will always have some ticks delay as absolute timestamp is calculated | ||
* after calling multiple functions. | ||
* _xtimer_tsleep32 | ||
* _xtimer_tsleep | ||
* _xtimer_set64 | ||
* _xtimer_set | ||
* */ | ||
for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) { | ||
uint32_t start, end, diff; | ||
|
||
start = _xtimer_now(); | ||
_xtimer_tsleep32(sleep_times[n]); | ||
end = _xtimer_now(); | ||
|
||
diff = end - start; | ||
printf("%" PRIu32 " %" PRIu32 " slept for %" PRIu32 " ticks (%" PRIu32 | ||
" us) expected %" PRIu32 " ticks, diff %" PRIu32 " ticks\n", | ||
start, end, diff, _xtimer_usec_from_ticks(diff), | ||
sleep_times[n], diff - sleep_times[n]); | ||
} | ||
|
||
/* Testing XTIMER_ISR_BACKOFF */ | ||
/* When only one timer is triggered the delay is smaller as less functions | ||
* are called untill absolute timestamp is calculated then for _xtimer_tsleep32. | ||
* _xtimer_set_wakeup | ||
* _xtimer_set | ||
*/ | ||
xtimer_t xtimer[SLEEP_TIMES_NUMOF]; | ||
uint32_t start[SLEEP_TIMES_NUMOF]; | ||
uint32_t interval[SLEEP_TIMES_NUMOF]; | ||
|
||
kernel_pid_t pid_main = thread_getpid(); | ||
|
||
kernel_pid_t pid_1 = thread_create(stack, | ||
sizeof(stack), | ||
THREAD_PRIORITY_MAIN - 1, | ||
THREAD_CREATE_STACKTEST, | ||
_thread, | ||
NULL, | ||
"second_thread"); | ||
|
||
interval[SLEEP_TIMES_NUMOF - 2] = _xtimer_usec_from_ticks(40000 + 15 + XTIMER_ISR_BACKOFF); | ||
start[SLEEP_TIMES_NUMOF - 2] = _xtimer_now(); | ||
xtimer_set_wakeup(&xtimer[SLEEP_TIMES_NUMOF - 2], interval[SLEEP_TIMES_NUMOF - 2], pid_main); | ||
|
||
interval[SLEEP_TIMES_NUMOF - 1] = _xtimer_usec_from_ticks(40000 + (XTIMER_ISR_BACKOFF * SLEEP_TIMES_NUMOF * 2) + 15 * SLEEP_TIMES_NUMOF); | ||
start[SLEEP_TIMES_NUMOF - 1] = _xtimer_now(); | ||
xtimer_set_wakeup(&xtimer[SLEEP_TIMES_NUMOF - 1], interval[SLEEP_TIMES_NUMOF - 1], pid_main); | ||
|
||
for (unsigned n = 0; n < (SLEEP_TIMES_NUMOF - 2); n++) { | ||
interval[n] = _xtimer_usec_from_ticks(40000 + (XTIMER_ISR_BACKOFF * n * 2)); | ||
start[n] = _xtimer_now(); | ||
xtimer_set_wakeup(&xtimer[n], interval[n], pid_1); | ||
} | ||
|
||
thread_sleep(); | ||
end_times[SLEEP_TIMES_NUMOF - 2] = _xtimer_now(); | ||
|
||
thread_sleep(); | ||
end_times[SLEEP_TIMES_NUMOF - 1] = _xtimer_now(); | ||
|
||
for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) { | ||
uint32_t diff = end_times[n] - start[n]; | ||
printf("%" PRIu32 " %" PRIu32 " slept for %" PRIu32 " ticks (%" PRIu32 | ||
" us) expected %" PRIu32 " ticks, diff %" PRIu32 " ticks\n", | ||
start[n], end_times[n], diff, _xtimer_usec_from_ticks(diff), | ||
_xtimer_ticks_from_usec(interval[n]), diff - _xtimer_ticks_from_usec(interval[n])); | ||
} | ||
|
||
testtime = xtimer_now_usec() - start_test; | ||
printf("Test ran for %" PRIu32 " us\n", testtime); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
# vim:fenc=utf-8 | ||
|
||
# Copyright (C) 2017 Francisco Acosta <francisco.acosta@inria.fr> | ||
# 2017 Freie Universität Berlin | ||
# | ||
# 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 os | ||
import sys | ||
import time | ||
|
||
US_PER_SEC = 1000000 | ||
INTERNAL_JITTER = 0.05 | ||
EXTERNAL_JITTER = 0.15 | ||
|
||
|
||
class InvalidTimeout(Exception): | ||
pass | ||
|
||
|
||
def testfunc(child): | ||
child.expect(u"Running test (\\d+) times with (\\d+) distinct sleep times") | ||
RUNS = int(child.match.group(1)) | ||
SLEEP_TIMES_NUMOF = int(child.match.group(2)) | ||
try: | ||
child.expect_exact(u"Please hit any key and then ENTER to continue") | ||
child.sendline(u"a") | ||
start_test = time.time() | ||
for m in range(RUNS): | ||
for n in range(SLEEP_TIMES_NUMOF): | ||
child.expect(u"(\\d+) (\\d+) slept for (\\d+) ticks.* expected" + | ||
" (\\d+) ticks.* diff (\\d+) ticks") | ||
start = int(child.match.group(1)) | ||
end = int(child.match.group(2)) | ||
sleep_time = int(child.match.group(3)) | ||
exp = int(child.match.group(4)) | ||
lower_bound = exp - (exp * EXTERNAL_JITTER) | ||
upper_bound = exp + (exp * EXTERNAL_JITTER) | ||
time.sleep(0.001) | ||
|
||
#if end - start < exp: | ||
# raise InvalidTimeout("To big values %d < %d, xtimer fires too early." | ||
# % (sleep_time, exp)) | ||
#elif sleep_time - exp > exp*(1.1): | ||
# raise InvalidTimeout("Difference too big %d, reduce XTIMER_OVERHEAD." | ||
# % (sleep_time-exp)) | ||
if m == 0 and n == SLEEP_TIMES_NUMOF-1: | ||
print("Increase value for XTIMER_SHOOT_OVERHEAD or " | ||
"XTIMER_OVERHEAD %d" % (sleep_time-exp)) | ||
elif m == 1 and n == 0: | ||
print("Increase value for XTIMER_BACKOFF_OVERHEAD %d" % (sleep_time-exp)) | ||
elif exp/10 < 0 and not (lower_bound < sleep_time < upper_bound): | ||
raise InvalidTimeout("Invalid timeout %d, expected %d, xtimer " + | ||
"compared to host clock has to much deviation" | ||
% (sleep_time, exp)) | ||
|
||
testtime = (time.time() - start_test) * US_PER_SEC | ||
child.expect(u"Test ran for (\\d+) us") | ||
exp = int(child.match.group(1)) | ||
lower_bound = exp - (exp * EXTERNAL_JITTER) | ||
upper_bound = exp + (exp * EXTERNAL_JITTER) | ||
if not (lower_bound < testtime < upper_bound): | ||
raise InvalidTimeout("Host timer measured %d us (client measured %d us)" | ||
% (testtime, exp)) | ||
except InvalidTimeout as e: | ||
print(e) | ||
sys.exit(1) | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner')) | ||
from testrunner import run | ||
sys.exit(run(testfunc)) |