Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions sys/xtimer/xtimer.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2016 Eistec AB
* 2016 Eistec AB
* 2018 Josua Arndt
*
* 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
Expand All @@ -15,6 +16,7 @@
* @brief xtimer convenience functionality
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Josua Arndt <jarndt@ias.rwth-aachen.de>
* @}
*/

Expand Down Expand Up @@ -71,30 +73,46 @@ void _xtimer_tsleep(uint32_t offset, uint32_t long_offset)
}

void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) {

xtimer_t timer;
mutex_t mutex = MUTEX_INIT;

timer.callback = _callback_unlock_mutex;
timer.arg = (void*) &mutex;
uint32_t mult;

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;
/* last_wakeup < target, now overflowed but target not, target passed.
* now < last_wakeup < target */
/* target <= now , both overflowed, target passed.
* target < now < last_wakeup */
if ((*last_wakeup < target) || (target <= now)) {
/* now - target, will always be the difference. (modulo power of two) */
mult = ((uint32_t)(now - target)) / period;
/* Skip missed targets */
*last_wakeup = target + (mult * period);
return;
}
}
else {
/* base timer did not overflow */
if ((((*last_wakeup) <= target) && (target <= now))) {
/* target time has already passed */
goto out;
/* last_wakeup < now, now did not overflow
* target <= now AND target did not overflow, target passed
* last_wakeup <= target <= now */
/* The special case (*last_wakeup) = target happens when a period smaller
* then the minimum resolution of the xtimer_hz is requested. */
if ((target <= now) && ((*last_wakeup) <= target)) {
/* now - target, will always be the difference. (modulo power of two) */
mult = ((uint32_t)(now - target))/ period;
/* Skip missed targets */
*last_wakeup = target + (mult * period);
return;
}
}

timer.callback = _callback_unlock_mutex;
timer.arg = (void*) &mutex;

/*
* For large offsets, set an absolute target time.
* As that might cause an underflow, for small offsets, set a relative
Expand All @@ -113,9 +131,13 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) {
* 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);
DEBUG("xps, now: %9" PRIu32 ", tgt: %9" PRIu32 ", lst_wkp: %9" PRIu32 ", off: %9" PRIu32 "\n",
now, target, *last_wakeup, offset);
if (offset < XTIMER_PERIODIC_SPIN) {
_xtimer_spin(offset);
/* Skip for zero*/
if(offset != 0) {
_xtimer_spin(offset);
}
}
else {
if (offset < XTIMER_PERIODIC_RELATIVE) {
Expand All @@ -131,7 +153,7 @@ void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) {
_xtimer_set_absolute(&timer, target);
mutex_lock(&mutex);
}
out:

*last_wakeup = target;
}

Expand Down