diff --git a/drivers/nvram_spi/nvram-spi.c b/drivers/nvram_spi/nvram-spi.c index ee5538845..9ed5ee664 100644 --- a/drivers/nvram_spi/nvram-spi.c +++ b/drivers/nvram_spi/nvram-spi.c @@ -40,7 +40,7 @@ typedef enum { /** @brief Delay to wait between toggling CS pin, on most chips this can probably be * removed. */ -#define NVRAM_SPI_CS_TOGGLE_TICKS 1 +#define NVRAM_SPI_CS_TOGGLE_TICKS xtimer_ticks_from_usec(1) /** * @brief Copy data from system memory to NVRAM. diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index 12c0b7dc1..b40f15f0a 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -40,6 +40,24 @@ extern "C" { #endif +/** + * @brief xtimer timestamp (64 bit) + * + * @note This is a struct in order to make the xtimer API type strict + */ +typedef struct { + uint64_t ticks64; +} xtimer_ticks64_t; + +/** + * @brief xtimer timestamp (32 bit) + * + * @note This is a struct in order to make the xtimer API type strict + */ +typedef struct { + uint32_t ticks32; +} xtimer_ticks32_t; + /** * @brief xtimer callback type */ @@ -58,21 +76,21 @@ typedef struct xtimer { } xtimer_t; /** - * @brief get the current system time as 32bit microsecond value + * @brief get the current system time as 32bit time stamp value * - * @note Overflows every ~71minutes, thus returns xtimer_now64() % 32, - * but is more efficient. + * @note Overflows 2**32 ticks, thus returns xtimer_now64() % 32, + * but is cheaper. * - * @return current time as 32bit microsecond value + * @return current time as 32bit time stamp */ -static inline uint32_t xtimer_now(void); +static inline xtimer_ticks32_t xtimer_now(void); /** - * @brief get the current system time as 64bit microsecond value + * @brief get the current system time as 64bit time stamp * - * @return current time as 64bit microsecond value + * @return current time as 64bit time stamp */ -uint64_t xtimer_now64(void); +static inline xtimer_ticks64_t xtimer_now64(void); /** * @brief get the current system time into a timex_t @@ -98,7 +116,7 @@ void xtimer_init(void); * * @param[in] seconds the amount of seconds the thread should sleep */ -static void xtimer_sleep(uint32_t seconds); +static inline void xtimer_sleep(uint32_t seconds); /** * @brief Pause the execution of a thread for some microseconds @@ -109,18 +127,7 @@ static void xtimer_sleep(uint32_t seconds); * * @param[in] microseconds the amount of microseconds the thread should sleep */ -static void xtimer_usleep(uint32_t microseconds); - -/** - * @brief Stop execution of a thread for some time, 64bit version - * - * When called from an ISR, this function will spin and thus block the MCU for - * the specified amount in microseconds, so only use it there for *very* short - * periods, e.g., less then XTIMER_BACKOFF. - * - * @param[in] microseconds the amount of microseconds the thread should sleep - */ -static inline void xtimer_usleep64(uint64_t microseconds); +static inline void xtimer_usleep(uint32_t microseconds); /** * @brief Stop execution of a thread for some time @@ -133,16 +140,38 @@ static inline void xtimer_usleep64(uint64_t microseconds); * * @param[in] nanoseconds the amount of nanoseconds the thread should sleep */ -static void xtimer_nanosleep(uint32_t nanoseconds); +static inline void xtimer_nanosleep(uint32_t nanoseconds); + +/** + * @brief Stop execution of a thread for some time, 32bit version + * + * When called from an ISR, this function will spin and thus block the MCU for + * the specified amount, so only use it there for *very* short periods, + * e.g. less than XTIMER_BACKOFF. + * + * @param[in] ticks number of ticks the thread should sleep + */ +static inline void xtimer_tsleep32(xtimer_ticks32_t ticks); + +/** + * @brief Stop execution of a thread for some time, 64bit version + * + * When called from an ISR, this function will spin and thus block the MCU for + * the specified amount, so only use it there for *very* short periods, + * e.g. less than XTIMER_BACKOFF. + * + * @param[in] ticks number of ticks the thread should sleep + */ +static inline void xtimer_tsleep64(xtimer_ticks64_t ticks); /** * @brief Stop execution of a thread for some time, blocking * * This function will spin-block, so only use it *very* short periods. * - * @param[in] microseconds the amount of microseconds the thread should spin + * @param[in] ticks the number of xtimer ticks the thread should spin for */ -static inline void xtimer_spin(uint32_t microseconds); +static inline void xtimer_spin(xtimer_ticks32_t ticks); /** * @brief will cause the calling thread to be suspended until the absolute @@ -161,12 +190,12 @@ static inline void xtimer_spin(uint32_t microseconds); * @param[in] last_wakeup base time stamp for the wakeup * @param[in] period time in microseconds that will be added to last_wakeup */ -void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period); +static inline void xtimer_periodic_wakeup(xtimer_ticks32_t *last_wakeup, uint32_t period); /** * @brief Set a timer that sends a message * - * This function sets a timer that will send a message @p offset microseconds + * This function sets a timer that will send a message @p offset ticks * from now. * * The mesage struct specified by msg parameter will not be copied, e.g., it @@ -179,7 +208,7 @@ void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period); * @param[in] msg ptr to msg that will be sent * @param[in] target_pid pid the message will be sent to */ -void xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid); +static inline void xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t target_pid); /** * @brief Set a timer that sends a message, 64bit version @@ -197,7 +226,7 @@ void xtimer_set_msg(xtimer_t *timer, uint32_t offset, msg_t *msg, kernel_pid_t t * @param[in] msg ptr to msg that will be sent * @param[in] target_pid pid the message will be sent to */ -void xtimer_set_msg64(xtimer_t *timer, uint64_t offset, msg_t *msg, kernel_pid_t target_pid); +static inline void xtimer_set_msg64(xtimer_t *timer, uint64_t offset, msg_t *msg, kernel_pid_t target_pid); /** * @brief Set a timer that wakes up a thread @@ -211,7 +240,7 @@ void xtimer_set_msg64(xtimer_t *timer, uint64_t offset, msg_t *msg, kernel_pid_t * @param[in] offset microseconds from now * @param[in] pid pid of the thread that will be woken up */ -void xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid); +static inline void xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid); /** * @brief Set a timer that wakes up a thread, 64bit version @@ -225,7 +254,7 @@ void xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid); * @param[in] offset microseconds from now * @param[in] pid pid of the thread that will be woken up */ -void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid); +static inline void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid); /** * @brief Set a timer to execute a callback at some time in the future @@ -233,7 +262,7 @@ void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid); * Expects timer->callback to be set. * * The callback specified in the timer struct will be executed @p offset - * microseconds in the future. + * ticks in the future. * * @warning BEWARE! Callbacks from xtimer_set() are being executed in interrupt * context (unless offset < XTIMER_BACKOFF). DON'T USE THIS FUNCTION unless you @@ -245,7 +274,7 @@ void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid); * @param[in] offset time in microseconds from now specifying that timer's * callback's execution time */ -void xtimer_set(xtimer_t *timer, uint32_t offset); +static inline void xtimer_set(xtimer_t *timer, uint32_t offset); /** * @brief remove a timer @@ -259,24 +288,78 @@ void xtimer_remove(xtimer_t *timer); /** * @brief receive a message blocking but with timeout * - * @param[out] msg pointer to a msg_t which will be filled in case of + * @param[out] msg pointer to a msg_t which will be filled in case of * no timeout - * @param[in] us timeout in microseconds relative + * @param[in] timeout timeout in microseconds relative * - * @return < 0 on error, other value otherwise + * @return < 0 on error, other value otherwise */ -int xtimer_msg_receive_timeout(msg_t *msg, uint32_t us); +static inline int xtimer_msg_receive_timeout(msg_t *msg, uint32_t timeout); /** * @brief receive a message blocking but with timeout, 64bit version * - * @param[out] msg pointer to a msg_t which will be filled in case of no + * @param[out] msg pointer to a msg_t which will be filled in case of no * timeout - * @param[in] us timeout in microseconds relative + * @param[in] timeout timeout in microseconds relative + * + * @return < 0 on error, other value otherwise + */ +static inline int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t timeout); + +/** + * @brief Convert microseconds to xtimer ticks + * + * @param[in] usec microseconds * - * @return < 0 on error, other value otherwise + * @return xtimer time stamp */ -int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us); +static inline xtimer_ticks32_t xtimer_ticks_from_usec(uint32_t usec); + +/** + * @brief Convert microseconds to xtimer ticks, 64 bit version + * + * @param[in] usec microseconds + * + * @return xtimer time stamp + */ +static inline xtimer_ticks64_t xtimer_ticks_from_usec64(uint64_t usec); + +/** + * @brief Convert xtimer ticks to microseconds + * + * @param[in] ticks xtimer time stamp + * + * @return microseconds + */ +static inline uint32_t xtimer_usec_from_ticks(xtimer_ticks32_t ticks); + +/** + * @brief Convert xtimer ticks to microseconds, 64 bit version + * + * @param[in] ticks xtimer time stamp + * + * @return microseconds + */ +static inline uint64_t xtimer_usec_from_ticks64(xtimer_ticks64_t ticks); + +/** + * @brief Create an xtimer time stamp + * + * @param[in] ticks number of xtimer ticks + * + * @return xtimer time stamp + */ +static inline xtimer_ticks32_t xtimer_ticks(uint32_t ticks); + +/** + * @brief Create an xtimer time stamp, 64 bit version + * + * @param[in] ticks number of xtimer ticks + * + * @return xtimer time stamp + */ +static inline xtimer_ticks64_t xtimer_ticks64(uint64_t ticks); /** * @brief xtimer backoff value @@ -291,7 +374,7 @@ int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us); #endif /** - * @brief xtimer overhead value + * @brief xtimer overhead value, in hardware ticks * * This value specifies the time a timer will be late if uncorrected, e.g., * the system-specific xtimer execution time from timer ISR to executing @@ -315,9 +398,9 @@ int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us); #ifndef XTIMER_ISR_BACKOFF /** - * @brief xtimer isr backoff time + * @brief xtimer IRQ backoff time, in hardware ticks * - * When scheduling the next isr, if it is less than the backoff time + * When scheduling the next IRQ, if it is less than the backoff time * in the future, just spin. * * This is supposed to be defined per-device in e.g., periph_conf.h. @@ -352,14 +435,16 @@ int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t us); /** * @brief xtimer prescaler value * - * xtimer assumes it is running with an underlying 1MHz timer. - * If the timer is slower by a power of two, XTIMER_SHIFT can be used to - * adjust the difference. + * If the underlying hardware timer is running at a power of two multiple of + * 15625, XTIMER_SHIFT can be used to adjust the difference. + * + * For a 1 MHz hardware timer, set XTIMER_SHIFT to 0. * - * This will also initialize the underlying periph timer with - * us_per_tick == (1<> -XTIMER_SHIFT ) -#else -#define XTIMER_USEC_TO_TICKS(value) ( (value) >> XTIMER_SHIFT ) -#define XTIMER_TICKS_TO_USEC(value) ( (value) << XTIMER_SHIFT ) -#endif - /** * @brief IPC message type for xtimer msg callback */ @@ -51,11 +43,7 @@ extern volatile uint32_t _xtimer_high_cnt; */ static inline uint32_t _xtimer_lltimer_now(void) { -#if XTIMER_SHIFT - return XTIMER_TICKS_TO_USEC((uint32_t)timer_read(XTIMER_DEV)); -#else return timer_read(XTIMER_DEV); -#endif } /** @@ -63,7 +51,7 @@ static inline uint32_t _xtimer_lltimer_now(void) */ static inline uint32_t _xtimer_lltimer_mask(uint32_t val) { - return val & ~XTIMER_MASK_SHIFTED; + return val & ~XTIMER_MASK; } /** @@ -71,22 +59,36 @@ static inline uint32_t _xtimer_lltimer_mask(uint32_t val) * @brief xtimer internal stuff * @internal */ +uint64_t _xtimer_now64(void); 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_sleep(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_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); +void _xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid); +void _xtimer_set(xtimer_t *timer, uint32_t offset); +int _xtimer_msg_receive_timeout(msg_t *msg, uint32_t ticks); +int _xtimer_msg_receive_timeout64(msg_t *msg, uint64_t ticks); + +/** + * @brief Sleep for the given number of ticks + */ +void _xtimer_tsleep(uint32_t offset, uint32_t long_offset); /** @} */ #ifndef XTIMER_MIN_SPIN /** * @brief Minimal value xtimer_spin() can spin */ -#define XTIMER_MIN_SPIN XTIMER_TICKS_TO_USEC(1) +#define XTIMER_MIN_SPIN _xtimer_usec_from_ticks(1) #endif #ifndef DOXYGEN /* Doxygen warns that these are undocumented, but the documentation can be found in xtimer.h */ -static inline uint32_t xtimer_now(void) +static inline uint32_t _xtimer_now(void) { #if XTIMER_MASK uint32_t latched_high_cnt, now; @@ -106,7 +108,19 @@ static inline uint32_t xtimer_now(void) #endif } -static inline void xtimer_spin(uint32_t offset) { +static inline xtimer_ticks32_t xtimer_now(void) +{ + xtimer_ticks32_t ret = { .ticks32 = _xtimer_now() }; + return ret; +} + +static inline xtimer_ticks64_t xtimer_now64(void) +{ + xtimer_ticks64_t ret = { .ticks64 = _xtimer_now64() }; + return ret; +} + +static inline void _xtimer_spin(uint32_t offset) { uint32_t start = _xtimer_lltimer_now(); #if XTIMER_MASK offset = _xtimer_lltimer_mask(offset); @@ -116,24 +130,122 @@ static inline void xtimer_spin(uint32_t offset) { #endif } +static inline void _xtimer_tsleep32(uint32_t ticks) +{ + _xtimer_tsleep(ticks, 0); +} + +static inline void _xtimer_tsleep64(uint64_t ticks) +{ + _xtimer_tsleep((uint32_t)ticks, (uint32_t)(ticks >> 32)); +} + +static inline void xtimer_spin(xtimer_ticks32_t ticks) { + _xtimer_spin(ticks.ticks32); +} + static inline void xtimer_usleep(uint32_t microseconds) { - _xtimer_sleep(microseconds, 0); + _xtimer_tsleep32(_xtimer_ticks_from_usec(microseconds)); } static inline void xtimer_usleep64(uint64_t microseconds) { - _xtimer_sleep((uint32_t) microseconds, (uint32_t) (microseconds >> 32)); + _xtimer_tsleep64(_xtimer_ticks_from_usec64(microseconds)); } static inline void xtimer_sleep(uint32_t seconds) { - xtimer_usleep64((uint64_t)seconds * SEC_IN_USEC); + _xtimer_tsleep64(_xtimer_ticks_from_usec64((uint64_t)seconds * SEC_IN_USEC)); } static inline void xtimer_nanosleep(uint32_t nanoseconds) { - _xtimer_sleep(nanoseconds / USEC_IN_NS, 0); + _xtimer_tsleep32(_xtimer_ticks_from_usec(nanoseconds / USEC_IN_NS)); +} + +static inline void xtimer_tsleep32(xtimer_ticks32_t ticks) +{ + _xtimer_tsleep32(ticks.ticks32); +} + +static inline void xtimer_tsleep64(xtimer_ticks64_t ticks) +{ + _xtimer_tsleep64(ticks.ticks64); +} + +static inline void xtimer_periodic_wakeup(xtimer_ticks32_t *last_wakeup, uint32_t period) +{ + _xtimer_periodic_wakeup(&last_wakeup->ticks32, _xtimer_ticks_from_usec(period)); +} + +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); +} + +static inline void xtimer_set_msg64(xtimer_t *timer, uint64_t offset, msg_t *msg, kernel_pid_t target_pid) +{ + _xtimer_set_msg64(timer, _xtimer_ticks_from_usec64(offset), msg, target_pid); +} + +static inline void xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid) +{ + _xtimer_set_wakeup(timer, _xtimer_ticks_from_usec(offset), pid); +} + +static inline void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid) +{ + _xtimer_set_wakeup64(timer, _xtimer_ticks_from_usec64(offset), pid); +} + +static inline void xtimer_set(xtimer_t *timer, uint32_t offset) +{ + _xtimer_set(timer, _xtimer_ticks_from_usec(offset)); +} + +static inline int xtimer_msg_receive_timeout(msg_t *msg, uint32_t timeout) +{ + return _xtimer_msg_receive_timeout(msg, _xtimer_ticks_from_usec(timeout)); +} + +static inline int xtimer_msg_receive_timeout64(msg_t *msg, uint64_t timeout) +{ + return _xtimer_msg_receive_timeout64(msg, _xtimer_ticks_from_usec64(timeout)); +} + +static inline xtimer_ticks32_t xtimer_ticks_from_usec(uint32_t usec) +{ + xtimer_ticks32_t ticks = { .ticks32 = _xtimer_ticks_from_usec(usec) }; + return ticks; +} + +static inline xtimer_ticks64_t xtimer_ticks_from_usec64(uint64_t usec) +{ + xtimer_ticks64_t ticks = { .ticks64 = _xtimer_ticks_from_usec64(usec) }; + return ticks; +} + +static inline uint32_t xtimer_usec_from_ticks(xtimer_ticks32_t ticks) +{ + return _xtimer_usec_from_ticks(ticks.ticks32); +} + +static inline uint64_t xtimer_usec_from_ticks64(xtimer_ticks64_t ticks) +{ + return _xtimer_usec_from_ticks64(ticks.ticks64); +} + +static inline xtimer_ticks32_t xtimer_ticks(uint32_t ticks) +{ + xtimer_ticks32_t ret = { .ticks32 = ticks }; + return ret; +} + +static inline xtimer_ticks64_t xtimer_ticks64(uint64_t ticks) +{ + xtimer_ticks64_t ret = { .ticks64 = ticks }; + return ret; } #endif /* !defined(DOXYGEN) */ diff --git a/sys/include/xtimer/tick_conversion.h b/sys/include/xtimer/tick_conversion.h new file mode 100644 index 000000000..7ceb77e05 --- /dev/null +++ b/sys/include/xtimer/tick_conversion.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016 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 sys_xtimer + * + * @{ + * @file + * @brief xtimer tick <-> seconds conversions for different values of XTIMER_HZ + * @author Joakim NohlgÄrd + */ + +#ifndef XTIMER_TICK_CONVERSION_H +#define XTIMER_TICK_CONVERSION_H + +#ifndef XTIMER_H +#error "Do not include this file directly! Use xtimer.h instead" +#endif + +#include "div.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Some optimizations for common timer frequencies */ +#if (XTIMER_SHIFT != 0) +#if (XTIMER_HZ % 15625 != 0) +#error XTIMER_HZ must be a multiple of 15625 (5^6) when using XTIMER_SHIFT +#endif +#if (XTIMER_HZ > 1000000ul) +#if (XTIMER_HZ != (1000000ul << XTIMER_SHIFT)) +#error XTIMER_HZ != (1000000ul << XTIMER_SHIFT) +#endif +/* XTIMER_HZ is a power-of-two multiple of 1 MHz */ +/* e.g. cc2538 uses a 16 MHz timer */ +inline static uint32_t _xtimer_ticks_from_usec(uint32_t usec) { + return (usec << XTIMER_SHIFT); /* multiply by power of two */ +} + +inline static uint64_t _xtimer_ticks_from_usec64(uint64_t usec) { + return (usec << XTIMER_SHIFT); /* multiply by power of two */ +} + +inline static uint32_t _xtimer_usec_from_ticks(uint32_t ticks) { + return (ticks >> XTIMER_SHIFT); /* divide by power of two */ +} + +inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) { + return (ticks >> XTIMER_SHIFT); /* divide by power of two */ +} + +#else /* !(XTIMER_HZ > 1000000ul) */ +#if ((XTIMER_HZ << XTIMER_SHIFT) != 1000000ul) +#error (XTIMER_HZ << XTIMER_SHIFT) != 1000000ul +#endif +/* 1 MHz is a power-of-two multiple of XTIMER_HZ */ +/* e.g. ATmega2560 uses a 250 kHz timer */ +inline static uint32_t _xtimer_ticks_from_usec(uint32_t usec) { + return (usec >> XTIMER_SHIFT); /* divide by power of two */ +} + +inline static uint64_t _xtimer_ticks_from_usec64(uint64_t usec) { + return (usec >> XTIMER_SHIFT); /* divide by power of two */ +} + +inline static uint32_t _xtimer_usec_from_ticks(uint32_t ticks) { + return (ticks << XTIMER_SHIFT); /* multiply by power of two */ +} + +inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) { + return (ticks << XTIMER_SHIFT); /* multiply by power of two */ +} +#endif /* defined(XTIMER_SHIFT) && (XTIMER_SHIFT != 0) */ +#elif XTIMER_HZ == (1000000ul) +/* This is the most straightforward as the xtimer API is based around + * microseconds for representing time values. */ +inline static uint32_t _xtimer_usec_from_ticks(uint32_t ticks) { + return ticks; /* no-op */ +} + +inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) { + return ticks; /* no-op */ +} + +inline static uint32_t _xtimer_ticks_from_usec(uint32_t usec) { + return usec; /* no-op */ +} + +inline static uint64_t _xtimer_ticks_from_usec64(uint64_t usec) { + return usec; /* no-op */ +} + +#elif XTIMER_HZ == (32768ul) +/* This is a common frequency for RTC crystals. We use the fact that the + * greatest common divisor between 32768 and 1000000 is 64, so instead of + * multiplying by the fraction (32768 / 1000000), we will instead use + * (512 / 15625), which reduces the truncation caused by the integer widths */ +inline static uint32_t _xtimer_ticks_from_usec(uint32_t usec) { + return div_u32_by_15625div512(usec); +} + +inline static uint64_t _xtimer_ticks_from_usec64(uint64_t usec) { + return div_u64_by_15625div512(usec); +} + +inline static uint32_t _xtimer_usec_from_ticks(uint32_t ticks) { + /* return (usec * 15625) / 512; */ + /* Using 64 bit multiplication to avoid truncating the top 9 bits */ + uint64_t usec = (uint64_t)ticks * 15625ul; + return (usec >> 9); /* equivalent to (usec / 512) */ +} + +inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) { + /* return (usec * 15625) / 512; */ + uint64_t usec = (uint64_t)ticks * 15625ul; + return (usec >> 9); /* equivalent to (usec / 512) */ +} + +#else +/* No matching implementation found, try to give meaningful error messages */ +#if ((XTIMER_HZ % 15625) == 0) +#error Unsupported hardware timer frequency (XTIMER_HZ), missing XTIMER_SHIFT in board.h? See xtimer.h documentation for more info +#else +#error Unknown hardware timer frequency (XTIMER_HZ), check board.h and/or add an implementation in sys/include/xtimer/tick_conversion.h +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sys/newlib/syscalls.c b/sys/newlib/syscalls.c index 56667e401..db9829716 100644 --- a/sys/newlib/syscalls.c +++ b/sys/newlib/syscalls.c @@ -340,7 +340,7 @@ int _gettimeofday_r(struct _reent *r, struct timeval *restrict tp, void *restric { (void)tzp; (void) r; - uint64_t now = xtimer_now64(); + uint64_t now = xtimer_usec_from_ticks64(xtimer_now64()); tp->tv_sec = div_u64_by_1000000(now); tp->tv_usec = now - (tp->tv_sec * SEC_IN_USEC); return 0; diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index efe19d635..f55da0b58 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -38,11 +38,11 @@ static void _callback_unlock_mutex(void* arg) mutex_unlock(mutex); } -void _xtimer_sleep(uint32_t offset, uint32_t long_offset) +void _xtimer_tsleep(uint32_t offset, uint32_t long_offset) { if (irq_is_in()) { assert(!long_offset); - xtimer_spin(offset); + _xtimer_spin(offset); return; } @@ -58,7 +58,7 @@ void _xtimer_sleep(uint32_t offset, uint32_t long_offset) mutex_lock(&mutex); } -void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { +void _xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { xtimer_t timer; mutex_t mutex = MUTEX_INIT; @@ -66,7 +66,7 @@ void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { timer.arg = (void*) &mutex; uint32_t target = (*last_wakeup) + period; - uint32_t now = xtimer_now(); + 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 */ @@ -103,7 +103,7 @@ void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { 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); + _xtimer_spin(offset); } else { if (offset < XTIMER_PERIODIC_RELATIVE) { @@ -112,14 +112,13 @@ void xtimer_periodic_wakeup(uint32_t *last_wakeup, uint32_t period) { * * Since interrupts are normally enabled inside this function, this time may * be undeterministic. */ - target = xtimer_now() + offset; + target = _xtimer_now() + offset; } mutex_lock(&mutex); DEBUG("xps, abs: %" PRIu32 "\n", target); _xtimer_set_absolute(&timer, target); mutex_lock(&mutex); } - out: *last_wakeup = target; } @@ -139,13 +138,13 @@ static inline void _setup_msg(xtimer_t *timer, msg_t *msg, kernel_pid_t target_p msg->sender_pid = target_pid; } -void xtimer_set_msg(xtimer_t *timer, uint32_t offset, 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) { _setup_msg(timer, msg, target_pid); - xtimer_set(timer, offset); + _xtimer_set(timer, offset); } -void xtimer_set_msg64(xtimer_t *timer, uint64_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) { _setup_msg(timer, msg, target_pid); _xtimer_set64(timer, offset, offset >> 32); @@ -156,15 +155,15 @@ static void _callback_wakeup(void* arg) thread_wakeup((kernel_pid_t)((intptr_t)arg)); } -void xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid) +void _xtimer_set_wakeup(xtimer_t *timer, uint32_t offset, kernel_pid_t pid) { timer->callback = _callback_wakeup; timer->arg = (void*) ((intptr_t)pid); - xtimer_set(timer, offset); + _xtimer_set(timer, offset); } -void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid) +void _xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid) { timer->callback = _callback_wakeup; timer->arg = (void*) ((intptr_t)pid); @@ -174,7 +173,7 @@ void xtimer_set_wakeup64(xtimer_t *timer, uint64_t offset, kernel_pid_t pid) void xtimer_now_timex(timex_t *out) { - uint64_t now = xtimer_now64(); + uint64_t now = xtimer_usec_from_ticks64(xtimer_now64()); out->seconds = div_u64_by_1000000(now); out->microseconds = now - (out->seconds * SEC_IN_USEC); @@ -205,19 +204,19 @@ static int _msg_wait(msg_t *m, msg_t *tmsg, xtimer_t *t) } } -int xtimer_msg_receive_timeout64(msg_t *m, uint64_t timeout) { +int _xtimer_msg_receive_timeout64(msg_t *m, uint64_t timeout_ticks) { msg_t tmsg; xtimer_t t; _setup_timer_msg(&tmsg, &t); - xtimer_set_msg64(&t, timeout, &tmsg, sched_active_pid); + _xtimer_set_msg64(&t, timeout_ticks, &tmsg, sched_active_pid); return _msg_wait(m, &tmsg, &t); } -int xtimer_msg_receive_timeout(msg_t *msg, uint32_t us) +int _xtimer_msg_receive_timeout(msg_t *msg, uint32_t timeout_ticks) { msg_t tmsg; xtimer_t t; _setup_timer_msg(&tmsg, &t); - xtimer_set_msg(&t, us, &tmsg, sched_active_pid); + _xtimer_set_msg(&t, timeout_ticks, &tmsg, sched_active_pid); return _msg_wait(msg, &tmsg, &t); } diff --git a/sys/xtimer/xtimer_core.c b/sys/xtimer/xtimer_core.c index 45140d7b1..72551bc6f 100644 --- a/sys/xtimer/xtimer_core.c +++ b/sys/xtimer/xtimer_core.c @@ -69,21 +69,21 @@ static inline void xtimer_spin_until(uint32_t target) { void xtimer_init(void) { /* initialize low-level timer */ - timer_init(XTIMER_DEV, XTIMER_USEC_TO_TICKS(1000000ul), _periph_timer_callback, NULL); + timer_init(XTIMER_DEV, XTIMER_HZ, _periph_timer_callback, NULL); /* register initial overflow tick */ _lltimer_set(0xFFFFFFFF); } -static void _xtimer_now64(uint32_t *short_term, uint32_t *long_term) +static void _xtimer_now_internal(uint32_t *short_term, uint32_t *long_term) { uint32_t before, after, long_value; - /* loop to cope with possible overflow of xtimer_now() */ + /* loop to cope with possible overflow of _xtimer_now() */ do { - before = xtimer_now(); + before = _xtimer_now(); long_value = _long_cnt; - after = xtimer_now(); + after = _xtimer_now(); } while(before > after); @@ -91,10 +91,10 @@ static void _xtimer_now64(uint32_t *short_term, uint32_t *long_term) *long_term = long_value; } -uint64_t xtimer_now64(void) +uint64_t _xtimer_now64(void) { uint32_t short_term, long_term; - _xtimer_now64(&short_term, &long_term); + _xtimer_now_internal(&short_term, &long_term); return ((uint64_t)long_term<<32) + short_term; } @@ -104,7 +104,7 @@ void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset) DEBUG(" _xtimer_set64() offset=%" PRIu32 " long_offset=%" PRIu32 "\n", offset, long_offset); if (!long_offset) { /* timer fits into the short timer */ - xtimer_set(timer, (uint32_t) offset); + _xtimer_set(timer, (uint32_t) offset); } else { int state = irq_disable(); @@ -112,7 +112,7 @@ void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset) _remove(timer); } - _xtimer_now64(&timer->target, &timer->long_target); + _xtimer_now_internal(&timer->target, &timer->long_target); timer->target += offset; timer->long_target += long_offset; if (timer->target < offset) { @@ -126,7 +126,7 @@ void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset) } } -void xtimer_set(xtimer_t *timer, uint32_t offset) +void _xtimer_set(xtimer_t *timer, uint32_t offset) { DEBUG("timer_set(): offset=%" PRIu32 " now=%" PRIu32 " (%" PRIu32 ")\n", offset, xtimer_now(), _xtimer_lltimer_now()); if (!timer->callback) { @@ -137,11 +137,11 @@ void xtimer_set(xtimer_t *timer, uint32_t offset) xtimer_remove(timer); if (offset < XTIMER_BACKOFF) { - xtimer_spin(offset); + _xtimer_spin(offset); _shoot(timer); } else { - uint32_t target = xtimer_now() + offset; + uint32_t target = _xtimer_now() + offset; _xtimer_set_absolute(timer, target); } } @@ -164,18 +164,12 @@ static inline void _lltimer_set(uint32_t target) return; } DEBUG("_lltimer_set(): setting %" PRIu32 "\n", _xtimer_lltimer_mask(target)); -#ifdef XTIMER_SHIFT - target = XTIMER_USEC_TO_TICKS(target); - if (!target) { - target++; - } -#endif timer_set_absolute(XTIMER_DEV, XTIMER_CHAN, _xtimer_lltimer_mask(target)); } int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) { - uint32_t now = xtimer_now(); + uint32_t now = _xtimer_now(); int res = 0; DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target); @@ -309,7 +303,7 @@ static uint32_t _time_left(uint32_t target, uint32_t reference) static inline int _this_high_period(uint32_t target) { #if XTIMER_MASK - return (target & XTIMER_MASK_SHIFTED) == _xtimer_high_cnt; + return (target & XTIMER_MASK) == _xtimer_high_cnt; #else (void)target; return 1; @@ -413,7 +407,7 @@ static void _next_period(void) { #if XTIMER_MASK /* advance <32bit mask register */ - _xtimer_high_cnt += ~XTIMER_MASK_SHIFTED + 1; + _xtimer_high_cnt += ~XTIMER_MASK + 1; if (_xtimer_high_cnt == 0) { /* high_cnt overflowed, so advance >32bit counter */ _long_cnt++; diff --git a/tests/xtimer_drift/main.c b/tests/xtimer_drift/main.c index 7bb5828d9..2f200ffdf 100644 --- a/tests/xtimer_drift/main.c +++ b/tests/xtimer_drift/main.c @@ -79,7 +79,7 @@ void *slacker_thread(void *arg) tmsg->msg.type = 12345; tmsg->msg.content.ptr = tmsg; - xtimer_set_msg(&tmsg->timer, tmsg->interval, &tmsg->msg, thread_getpid()); + xtimer_set_msg(&tmsg->timer, xtimer_ticks_from_usec(tmsg->interval), &tmsg->msg, thread_getpid()); } } @@ -96,7 +96,7 @@ void *worker_thread(void *arg) while (1) { msg_t m; msg_receive(&m); - uint32_t now = xtimer_now(); + uint32_t now = xtimer_usec_from_ticks(xtimer_now()); if (start == 0) { start = now; last = start; @@ -190,9 +190,9 @@ int main(void) NULL, "worker"); - uint32_t last_wakeup = xtimer_now(); + xtimer_ticks32_t last_wakeup = xtimer_now(); while (1) { - xtimer_periodic_wakeup(&last_wakeup, TEST_INTERVAL); + xtimer_periodic_wakeup(&last_wakeup, xtimer_ticks_from_usec(TEST_INTERVAL)); msg_try_send(&m, pid3); } }