From f8b8be696c0c0f5f782f256b9de0e768a4f1b8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 10:22:06 +0200 Subject: [PATCH 01/10] xtimer: xtimer_set_msg: Minor documentation fixes --- sys/include/xtimer.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index 9ee060a01456..2e8649c850d0 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -210,11 +210,11 @@ static inline void xtimer_periodic_wakeup(xtimer_ticks32_t *last_wakeup, uint32_ /** * @brief Set a timer that sends a message * - * This function sets a timer that will send a message @p offset ticks + * This function sets a timer that will send a message @p offset microseconds * from now. * - * The mesage struct specified by msg parameter will not be copied, e.g., it - * needs to point to valid memory until the message has been delivered. + * @attention The message struct pointed to by @p msg will not be copied, + * i.e. it needs to point to valid memory until the message has been delivered. * * @param[in] timer timer struct to work with. * Its xtimer_t::target and xtimer_t::long_target @@ -231,8 +231,8 @@ static inline void xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, * This function sets a timer that will send a message @p offset microseconds * from now. * - * The mesage struct specified by msg parameter will not be copied, e.g., it - * needs to point to valid memory until the message has been delivered. + * @attention The message struct pointed to by @p msg will not be copied, + * i.e. it needs to point to valid memory until the message has been delivered. * * @param[in] timer timer struct to work with. * Its xtimer_t::target and xtimer_t::long_target From b69f25e9c055cb7bc629833c89b09c62d9fac4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 10:26:58 +0200 Subject: [PATCH 02/10] xtimer: Use MUTEX_INIT_LOCKED for initialization --- sys/xtimer/xtimer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index 612bbc9622ff..0a05c521c167 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -58,20 +58,19 @@ void _xtimer_tsleep(uint32_t offset, uint32_t long_offset) } xtimer_t timer; - mutex_t mutex = MUTEX_INIT; + mutex_t mutex = MUTEX_INIT_LOCKED; timer.callback = _callback_unlock_mutex; timer.arg = (void*) &mutex; timer.target = timer.long_target = 0; - mutex_lock(&mutex); _xtimer_set64(&timer, offset, long_offset); mutex_lock(&mutex); } void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { xtimer_t timer; - mutex_t mutex = MUTEX_INIT; + mutex_t mutex = MUTEX_INIT_LOCKED; timer.callback = _callback_unlock_mutex; timer.arg = (void*) &mutex; @@ -125,7 +124,6 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { * be undeterministic. */ target = _xtimer_now() + offset; } - mutex_lock(&mutex); DEBUG("xps, abs: %" PRIu32 "\n", target); _xtimer_set_absolute(&timer, target); mutex_lock(&mutex); From 8f9b15679b7c61dc8499369ec134427c932bf368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 10:32:53 +0200 Subject: [PATCH 03/10] xtimer: eliminate goto in xtimer_periodic_wakeup --- sys/xtimer/xtimer.c | 97 +++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index 0a05c521c167..3a81509f5ea0 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -77,58 +77,59 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { uint32_t target = (*last_wakeup) + period; uint32_t now = _xtimer_now(); - /* make sure we're not setting a value in the past */ - if (now < (*last_wakeup)) { - /* base timer overflowed between last_wakeup and now */ - if (!((now < target) && (target < (*last_wakeup)))) { - /* target time has already passed */ - goto out; + do { + /* make sure we're not setting a value in the past */ + if (now < (*last_wakeup)) { + /* base timer overflowed between last_wakeup and now */ + if (!((now < target) && (target < (*last_wakeup)))) { + /* target time has already passed */ + break; + } } - } - else { - /* base timer did not overflow */ - if ((((*last_wakeup) <= target) && (target <= now))) { - /* target time has already passed */ - goto out; + else { + /* base timer did not overflow */ + if ((((*last_wakeup) <= target) && (target <= now))) { + /* target time has already passed */ + break; + } } - } - /* - * For large offsets, set an absolute target time. - * As that might cause an underflow, for small offsets, set a relative - * target time. - * For very small offsets, spin. - */ - /* - * Note: last_wakeup _must never_ specify a time in the future after - * _xtimer_periodic_sleep returns. - * If this happens, last_wakeup may specify a time in the future when the - * next call to _xtimer_periodic_sleep is made, which in turn will trigger - * the overflow logic above and make the next timer fire too early, causing - * last_wakeup to point even further into the future, leading to a chain - * reaction. - * - * tl;dr Don't return too early! - */ - uint32_t offset = target - now; - DEBUG("xps, now: %9" PRIu32 ", tgt: %9" PRIu32 ", off: %9" PRIu32 "\n", now, target, offset); - if (offset < XTIMER_PERIODIC_SPIN) { - _xtimer_spin(offset); - } - else { - if (offset < XTIMER_PERIODIC_RELATIVE) { - /* NB: This will overshoot the target by the amount of time it took - * to get here from the beginning of xtimer_periodic_wakeup() - * - * Since interrupts are normally enabled inside this function, this time may - * be undeterministic. */ - target = _xtimer_now() + offset; + /* + * For large offsets, set an absolute target time. + * As that might cause an underflow, for small offsets, set a relative + * target time. + * For very small offsets, spin. + */ + /* + * Note: last_wakeup _must never_ specify a time in the future after + * _xtimer_periodic_sleep returns. + * If this happens, last_wakeup may specify a time in the future when the + * next call to _xtimer_periodic_sleep is made, which in turn will trigger + * the overflow logic above and make the next timer fire too early, causing + * last_wakeup to point even further into the future, leading to a chain + * reaction. + * + * tl;dr Don't return too early! + */ + uint32_t offset = target - now; + DEBUG("xps, now: %9" PRIu32 ", tgt: %9" PRIu32 ", off: %9" PRIu32 "\n", now, target, offset); + if (offset < XTIMER_PERIODIC_SPIN) { + _xtimer_spin(offset); } - DEBUG("xps, abs: %" PRIu32 "\n", target); - _xtimer_set_absolute(&timer, target); - mutex_lock(&mutex); - } -out: + else { + if (offset < XTIMER_PERIODIC_RELATIVE) { + /* NB: This will overshoot the target by the amount of time it took + * to get here from the beginning of xtimer_periodic_wakeup() + * + * Since interrupts are normally enabled inside this function, this time may + * be undeterministic. */ + target = _xtimer_now() + offset; + } + DEBUG("xps, abs: %" PRIu32 "\n", target); + _xtimer_set_absolute(&timer, target); + mutex_lock(&mutex); + } + } while (0); *last_wakeup = target; } From 1c999b1aefe21a6c706ed2e7c5594647dd3c6314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 10:36:16 +0200 Subject: [PATCH 04/10] xtimer: Split xtimer_periodic_wakeup into a generic xtimer_periodic --- sys/xtimer/xtimer.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index 3a81509f5ea0..6eed33727741 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2015 Kaspar Schleiser - * Copyright (C) 2016 Eistec AB + * Copyright (C) 2016-2017 Eistec AB * * 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 @@ -68,13 +68,8 @@ void _xtimer_tsleep(uint32_t offset, uint32_t long_offset) mutex_lock(&mutex); } -void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { - xtimer_t timer; - mutex_t mutex = MUTEX_INIT_LOCKED; - - timer.callback = _callback_unlock_mutex; - timer.arg = (void*) &mutex; - +void _xtimer_periodic(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period) +{ uint32_t target = (*last_wakeup) + period; uint32_t now = _xtimer_now(); do { @@ -83,6 +78,7 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { /* base timer overflowed between last_wakeup and now */ if (!((now < target) && (target < (*last_wakeup)))) { /* target time has already passed */ + timer->callback(timer->arg); break; } } @@ -90,6 +86,7 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { /* base timer did not overflow */ if ((((*last_wakeup) <= target) && (target <= now))) { /* target time has already passed */ + timer->callback(timer->arg); break; } } @@ -115,6 +112,7 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { DEBUG("xps, now: %9" PRIu32 ", tgt: %9" PRIu32 ", off: %9" PRIu32 "\n", now, target, offset); if (offset < XTIMER_PERIODIC_SPIN) { _xtimer_spin(offset); + timer->callback(timer->arg); } else { if (offset < XTIMER_PERIODIC_RELATIVE) { @@ -126,13 +124,22 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { target = _xtimer_now() + offset; } DEBUG("xps, abs: %" PRIu32 "\n", target); - _xtimer_set_absolute(&timer, target); - mutex_lock(&mutex); + _xtimer_set_absolute(timer, target); } } while (0); *last_wakeup = target; } +void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { + xtimer_t timer; + mutex_t mutex = MUTEX_INIT_LOCKED; + + timer.callback = _callback_unlock_mutex; + timer.arg = (void*) &mutex; + _xtimer_periodic(&timer, last_wakeup, period); + mutex_lock(&mutex); +} + static void _callback_msg(void* arg) { msg_t *msg = (msg_t*)arg; From d6c76a0aaf933726b7682cf07d876d8108753916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 11:48:41 +0200 Subject: [PATCH 05/10] xtimer: Add xtimer_periodic_msg --- sys/include/xtimer.h | 37 ++++++++++++++++++++++++++--- sys/include/xtimer/implementation.h | 10 +++++++- sys/xtimer/xtimer.c | 6 +++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index 2e8649c850d0..78388908c5af 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2015 Kaspar Schleiser - * Copyright (C) 2016 Eistec AB + * Copyright (C) 2016-2017 Eistec AB * * 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 @@ -71,8 +71,7 @@ typedef struct xtimer { struct xtimer *next; /**< reference to next timer in timer lists */ uint32_t target; /**< lower 32bit absolute target time */ uint32_t long_target; /**< upper 32bit absolute target time */ - xtimer_callback_t callback; /**< callback function to call when timer - expires */ + xtimer_callback_t callback; /**< callback function to call when timer expires */ void *arg; /**< argument to pass to callback function */ } xtimer_t; @@ -207,6 +206,38 @@ static inline void xtimer_spin(xtimer_ticks32_t ticks); */ static inline void xtimer_periodic_wakeup(xtimer_ticks32_t *last_wakeup, uint32_t period); +/** + * @brief Send a message at absolute time (@p last_wakeup + @p period) + * + * Functionally similar to xtimer_set_msg, but the target time is computed in + * the same way as for xtimer_periodic_wakeup. + * + * This function can be used to create periodic messages. This is especially + * useful if a thread has an event loop for handling asynchronous events, but + * some events need to occur periodically on a schedule. Using + * xtimer_periodic_wakeup in these kinds of applications would cause the + * asynchronous events to be delayed until the next wakeup, instead of processed + * immediately. + * + * @attention The message struct pointed to by @p msg will not be copied, + * i.e. it needs to point to valid memory until the message has been delivered. + * + * If the result of (@p last_wakeup + @p period) would be in the past, the function + * sets @p last_wakeup to @p last_wakeup + @p period and sends the message + * immediately. + * + * @param[in] timer timer struct to work with. + * Its xtimer_t::target and xtimer_t::long_target + * fields need to be initialized with 0 on first use. + * @param[in] last_wakeup base time stamp for the wakeup + * @param[in] period time in microseconds that will be added to last_wakeup + * @param[in] msg message that will be sent + * @param[in] target_pid destination thread PID + */ +static inline void xtimer_periodic_msg(xtimer_t *timer, + xtimer_ticks32_t *last_wakeup, uint32_t period, + msg_t *msg, kernel_pid_t target_pid); + /** * @brief Set a timer that sends a message * diff --git a/sys/include/xtimer/implementation.h b/sys/include/xtimer/implementation.h index 107ac99e91c8..e5f0c2ac76ea 100644 --- a/sys/include/xtimer/implementation.h +++ b/sys/include/xtimer/implementation.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2015 Kaspar Schleiser - * Copyright (C) 2016 Eistec AB + * Copyright (C) 2016-2017 Eistec AB * * 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 @@ -66,6 +66,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target); void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset); void _xtimer_set(xtimer_t *timer, uint32_t offset); void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period); +void _xtimer_periodic_msg(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period, msg_t *msg, kernel_pid_t target_pid); void _xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid); void _xtimer_set_msg64(xtimer_t *timer, uint64_t offset, msg_t *msg, kernel_pid_t target_pid); void _xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid); @@ -193,6 +194,13 @@ static inline void xtimer_periodic_wakeup(xtimer_ticks32_t *last_wakeup, uint32_ _xtimer_periodic_wakeup(&last_wakeup->ticks32, _xtimer_ticks_from_usec(period)); } +static inline void xtimer_periodic_msg(xtimer_t *timer, + xtimer_ticks32_t *last_wakeup, uint32_t period, + msg_t *msg, kernel_pid_t target_pid) +{ + _xtimer_periodic_msg(timer, &last_wakeup->ticks32, _xtimer_ticks_from_usec(period), msg, target_pid); +} + static inline void xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid) { _xtimer_set_msg(timer, _xtimer_ticks_from_usec(offset), msg, target_pid); diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index 6eed33727741..b5ef1e107cf1 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -155,6 +155,12 @@ static inline void _setup_msg(xtimer_t *timer, msg_t *msg, kernel_pid_t target_p msg->sender_pid = target_pid; } +void _xtimer_periodic_msg(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period, msg_t *msg, kernel_pid_t target_pid) +{ + _setup_msg(timer, msg, target_pid); + _xtimer_periodic(timer, last_wakeup, period); +} + void _xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid) { _setup_msg(timer, msg, target_pid); From dbab6f1faa191ec37fb8a378fa15e5c5843726bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 12:12:16 +0200 Subject: [PATCH 06/10] tests: Add xtimer_periodic_msg test application --- tests/xtimer_periodic_msg/Makefile | 6 +++ tests/xtimer_periodic_msg/main.c | 81 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/xtimer_periodic_msg/Makefile create mode 100644 tests/xtimer_periodic_msg/main.c diff --git a/tests/xtimer_periodic_msg/Makefile b/tests/xtimer_periodic_msg/Makefile new file mode 100644 index 000000000000..5d7c60b31f7c --- /dev/null +++ b/tests/xtimer_periodic_msg/Makefile @@ -0,0 +1,6 @@ +APPLICATION = xtimer_periodic_msg +include ../Makefile.tests_common + +USEMODULE += xtimer + +include $(RIOTBASE)/Makefile.include diff --git a/tests/xtimer_periodic_msg/main.c b/tests/xtimer_periodic_msg/main.c new file mode 100644 index 000000000000..6eaa75459e44 --- /dev/null +++ b/tests/xtimer_periodic_msg/main.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * Copyright (C) 2017 Eistec AB + * + * 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 timer test application + * + * @author Kaspar Schleiser + * @author Joakim NohlgÄrd + * + * @} + */ + +#include +#include "thread.h" +#include "msg.h" +#include "xtimer.h" + +#ifndef NUMOF +#define NUMOF (256) +#endif + +int32_t res[NUMOF]; + +int main(void) +{ + puts("xtimer_periodic_msg test application.\n"); + msg_t msg_q[1]; + msg_init_queue(msg_q, 1); + + uint32_t interval = NUMOF; + int32_t max_diff = INT32_MIN; + int32_t min_diff = INT32_MAX; + + for (int i = 0; i < NUMOF; i++) { + xtimer_ticks32_t now = xtimer_now(); + printf("Testing interval %" PRIu32 "... (now=%" PRIu32 ")\n", interval, xtimer_usec_from_ticks(now)); + xtimer_ticks32_t last_wakeup = xtimer_now(); + xtimer_ticks32_t before = last_wakeup; + xtimer_t timer = { .target = 0, .long_target = 0 }; + msg_t msg_out = { .type = 0xffff - interval, .content.value = interval }; + xtimer_periodic_msg(&timer, &last_wakeup, interval, &msg_out, thread_getpid()); + msg_t msg_in; + msg_receive(&msg_in); + now = xtimer_now(); + assert(msg_in.type == msg_out.type); + assert(msg_in.content.value == msg_out.content.value); + res[i] = (xtimer_usec_from_ticks(now) - xtimer_usec_from_ticks(before)) - interval; + interval -= 1; + } + + for (int i = 0; i < NUMOF; i++) { + printf("%4d diff=%" PRIi32 "\n", NUMOF - i, res[i]); + + if (res[i] > max_diff) { + max_diff = res[i]; + } + if (res[i] < min_diff) { + min_diff = res[i]; + } + } + printf("\nMin/max error: %" PRId32 "/%" PRId32 "\n", min_diff, max_diff); + + if (min_diff < -1000 || max_diff > 1000) { + puts("too large difference.\n"); + puts("Test Failed.\n"); + return 1; + } + + printf("\nTest complete.\n"); + return 0; +} From 67a83618ede253026b085282264ef3fac4716966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 22 Aug 2017 12:12:37 +0200 Subject: [PATCH 07/10] tests/xtimer_periodic_wakeup: Remove chronos blacklist --- tests/xtimer_periodic_wakeup/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/xtimer_periodic_wakeup/Makefile b/tests/xtimer_periodic_wakeup/Makefile index 4aa8d3febc23..66f16d50f9d9 100644 --- a/tests/xtimer_periodic_wakeup/Makefile +++ b/tests/xtimer_periodic_wakeup/Makefile @@ -1,8 +1,6 @@ APPLICATION = xtimer_periodic_wakeup include ../Makefile.tests_common -BOARD_INSUFFICIENT_MEMORY := chronos - USEMODULE += xtimer include $(RIOTBASE)/Makefile.include From 75c8d8dd1831851738ff58e95781bf0389ecc21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Tue, 19 Sep 2017 10:57:02 +0200 Subject: [PATCH 08/10] squash xtimer comment indentation --- sys/xtimer/xtimer.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index b5ef1e107cf1..a2a32dbebe73 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -92,22 +92,22 @@ void _xtimer_periodic(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period) } /* - * For large offsets, set an absolute target time. - * As that might cause an underflow, for small offsets, set a relative - * target time. - * For very small offsets, spin. - */ + * For large offsets, set an absolute target time. + * As that might cause an underflow, for small offsets, set a relative + * target time. + * For very small offsets, spin. + */ /* - * Note: last_wakeup _must never_ specify a time in the future after - * _xtimer_periodic_sleep returns. - * If this happens, last_wakeup may specify a time in the future when the - * next call to _xtimer_periodic_sleep is made, which in turn will trigger - * the overflow logic above and make the next timer fire too early, causing - * last_wakeup to point even further into the future, leading to a chain - * reaction. - * - * tl;dr Don't return too early! - */ + * Note: last_wakeup _must never_ specify a time in the future after + * _xtimer_periodic_sleep returns. + * If this happens, last_wakeup may specify a time in the future when the + * next call to _xtimer_periodic_sleep is made, which in turn will trigger + * the overflow logic above and make the next timer fire too early, causing + * last_wakeup to point even further into the future, leading to a chain + * reaction. + * + * tl;dr Don't return too early! + */ uint32_t offset = target - now; DEBUG("xps, now: %9" PRIu32 ", tgt: %9" PRIu32 ", off: %9" PRIu32 "\n", now, target, offset); if (offset < XTIMER_PERIODIC_SPIN) { @@ -117,10 +117,10 @@ void _xtimer_periodic(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period) else { if (offset < XTIMER_PERIODIC_RELATIVE) { /* NB: This will overshoot the target by the amount of time it took - * to get here from the beginning of xtimer_periodic_wakeup() - * - * Since interrupts are normally enabled inside this function, this time may - * be undeterministic. */ + * to get here from the beginning of xtimer_periodic_wakeup() + * + * Since interrupts are normally enabled inside this function, this time may + * be nondeterministic. */ target = _xtimer_now() + offset; } DEBUG("xps, abs: %" PRIu32 "\n", target); From e5e7d915d4de04eeb83957b83757d836002e666b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Wed, 20 Sep 2017 10:15:40 +0200 Subject: [PATCH 09/10] xtimer: Fix backoff condition in _xtimer_set_absolute When the target is inside the next long_period, the previous condition was incorrect. The new condition should give the same result regardless of whether there is a long_period tick coming soon or not. --- sys/xtimer/xtimer_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/xtimer/xtimer_core.c b/sys/xtimer/xtimer_core.c index d5765de89b84..33bd8c9aacda 100644 --- a/sys/xtimer/xtimer_core.c +++ b/sys/xtimer/xtimer_core.c @@ -176,7 +176,9 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target); timer->next = NULL; - if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) { + /* The (target - now) difference works across the long tick rollover, there + * is no need to check for (target > now) first. */ + if ((target - now) < XTIMER_BACKOFF) { /* backoff */ xtimer_spin_until(target + XTIMER_BACKOFF); _shoot(timer); From 84f42e21e5d8e00a1031e4f62b3bf274ee7af561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Thu, 14 Sep 2017 06:55:18 +0200 Subject: [PATCH 10/10] xtimer_periodic: Skip ahead when target time has already passed --- sys/xtimer/xtimer.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index a2a32dbebe73..0fcd786aec12 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -79,6 +79,20 @@ void _xtimer_periodic(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period) if (!((now < target) && (target < (*last_wakeup)))) { /* target time has already passed */ timer->callback(timer->arg); + /* Try to skip ahead until we are back on schedule */ + uint32_t catchup = period; + if (target < now) { + while((target < (target + catchup)) && ((target + catchup) <= now)) { + catchup += period; + } + } + else { + while(!((now < (target + catchup)) && ((target + catchup) < target))) { + catchup += period; + } + } + target += catchup - period; + DEBUG("cu: %" PRIx32 "\n", catchup); break; } } @@ -87,6 +101,13 @@ void _xtimer_periodic(xtimer_t *timer, uint32_t *last_wakeup, uint32_t period) if ((((*last_wakeup) <= target) && (target <= now))) { /* target time has already passed */ timer->callback(timer->arg); + /* Try to skip ahead until we are back on schedule */ + uint32_t catchup = period; + while((target < (target + catchup)) && ((target + catchup) <= now)) { + catchup += period; + } + target += catchup - period; + DEBUG("CU: %" PRIx32 "\n", catchup); break; } }