This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 6dcb8270e303012821c120098ebf7b52d2944d17 Author: ouyangxiangzhen <[email protected]> AuthorDate: Wed Jul 30 10:37:56 2025 +0800 timers/oneshot: Add new clkdev interfaces. This commit introduce new clockdevice interfaces for oneshot. - It can represent both `timer` and `alarm`. - It simplifies the implementation of timer driver. Timer driver do not need considering the time conversion between clock count, tick and timespec. - It sets timer align to the tick boundary to improve timer accuracy. - It can avoid using 64-bit division during timer expiration interrupt, improves performance and reduces interrupt latency. - It considers almost all multiplication overflow problems in time conversion without processing at the driver. Signed-off-by: ouyangxiangzhen <[email protected]> --- drivers/timers/Kconfig | 2 +- include/nuttx/timers/oneshot.h | 242 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 221 insertions(+), 23 deletions(-) diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig index 7cc2d4abc1f..62416e868af 100644 --- a/drivers/timers/Kconfig +++ b/drivers/timers/Kconfig @@ -124,7 +124,7 @@ config ONESHOT if ONESHOT config ONESHOT_COUNT - bool "Oneshot count-based clock device driver" + bool default n ---help--- This option enables the oneshot implementation to be based on the diff --git a/include/nuttx/timers/oneshot.h b/include/nuttx/timers/oneshot.h index 877c7acf086..302527588f9 100644 --- a/include/nuttx/timers/oneshot.h +++ b/include/nuttx/timers/oneshot.h @@ -96,8 +96,8 @@ * ****************************************************************************/ -#define ONESHOT_MAX_DELAY(l,t) (l)->ops->max_delay(l,t) -#define ONESHOT_TICK_MAX_DELAY(l,t) oneshot_tick_max_delay(l,t) +#define ONESHOT_MAX_DELAY(l,t) oneshot_max_delay(l,t) +#define ONESHOT_TICK_MAX_DELAY(l,t) oneshot_tick_max_delay(l,t) /**************************************************************************** * Name: ONESHOT_START @@ -119,7 +119,7 @@ * ****************************************************************************/ -#define ONESHOT_START(l,t) (l)->ops->start(l,t) +#define ONESHOT_START(l,t) oneshot_start(l,t) #define ONESHOT_TICK_START(l,t) oneshot_tick_start(l,t) /**************************************************************************** @@ -146,7 +146,7 @@ * ****************************************************************************/ -#define ONESHOT_CANCEL(l,t) (l)->ops->cancel(l,t) +#define ONESHOT_CANCEL(l,t) oneshot_cancel(l,t) #define ONESHOT_TICK_CANCEL(l,t) oneshot_tick_cancel(l,t) /**************************************************************************** @@ -168,7 +168,7 @@ * ****************************************************************************/ -#define ONESHOT_CURRENT(l,t) (l)->ops->current(l,t) +#define ONESHOT_CURRENT(l,t) oneshot_current(l,t) #define ONESHOT_TICK_CURRENT(l,t) oneshot_tick_current(l,t) /**************************************************************************** @@ -266,43 +266,205 @@ extern "C" * Inline Functions ****************************************************************************/ +#ifdef CONFIG_ONESHOT_COUNT +static inline_function +void oneshot_count_init(FAR struct oneshot_lowerhalf_s *lower, + uint32_t frequency) +{ + DEBUGASSERT(lower && frequency); + + lower->frequency = frequency; +} +#endif + +static inline_function +int oneshot_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + clkcnt_t max = lower->ops->max_delay(lower); + clkcnt_max_timespec(max, lower->frequency, ts); +#else + ret = lower->ops->max_delay(lower, ts); +#endif + return ret; +} + +/**************************************************************************** + * Name: oneshot_current + * + * Description: + * Get the current time. + * + * Input Parameters: + * ops - The oneshot interface. + * lower - The oneshot lowerhalf data. + * ts - The pointer to the current time. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline_function +int oneshot_current(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + clkcnt_t cnt = lower->ops->current(lower); + uint32_t freq = lower->frequency; + uint64_t sec = clkcnt_cnt2sec(cnt, freq); + + cnt -= sec * freq; + ts->tv_nsec = clkcnt_delta_cnt2nsec(cnt, freq); + ts->tv_sec = sec; +#else + ret = lower->ops->current(lower, ts); +#endif + return ret; +} + +/**************************************************************************** + * Name: oneshot_cancel + * + * Description: + * Cancel the timer + * + * Input Parameters: + * ops - The oneshot interface. + * ts - The delta time in timespec. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline_function +int oneshot_cancel(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + lower->ops->cancel(lower); + oneshot_current(lower, ts); +#else + ret = lower->ops->cancel(lower, ts); +#endif + return ret; +} + +/**************************************************************************** + * Name: oneshot_start + * + * Description: + * Set the relative time in timespec to trigger the clockevent. + * + * Input Parameters: + * ops - The oneshot interface. + * ts - The delta time in timespec. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline_function +int oneshot_start(FAR struct oneshot_lowerhalf_s *lower, + FAR const struct timespec *ts) +{ + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + clkcnt_t freq = lower->frequency; + clkcnt_t cnt = clkcnt_delta_time2cnt(ts->tv_nsec, freq, NSEC_PER_SEC) + + ts->tv_sec * freq; + + lower->ops->start(lower, cnt); +#else + ret = lower->ops->start(lower, ts); +#endif + return ret; +} + /* Tick-based compatiable layer for oneshot */ static inline_function int oneshot_tick_max_delay(FAR struct oneshot_lowerhalf_s *lower, FAR clock_t *tick) { + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + clkcnt_t max = lower->ops->max_delay(lower); + *tick = clkcnt_max_tick(max, lower->frequency); +#else struct timespec ts; - ONESHOT_MAX_DELAY(lower, &ts); + ret = lower->ops->max_delay(lower, &ts); *tick = clock_time2ticks(&ts); - - return OK; +#endif + return ret; } +/**************************************************************************** + * Name: oneshot_tick_start + * + * Description: + * Set the relative time in ticks to trigger the clockevent. + * + * Input Parameters: + * ops - The oneshot interface. + * tick - The delta time in ticks. + + * Returned Value: + * None. + * + ****************************************************************************/ + static inline_function int oneshot_tick_start(FAR struct oneshot_lowerhalf_s *lower, - clock_t ticks) + clock_t tick) { + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + clkcnt_t cnt = clkcnt_tick2cnt(tick, lower->frequency); + lower->ops->start(lower, cnt); +#else struct timespec ts; - clock_ticks2time(&ts, ticks); - return lower->ops->start(lower, &ts); + clock_ticks2time(&ts, tick); + ret = lower->ops->start(lower, &ts); +#endif + return ret; } -static inline_function -int oneshot_tick_cancel(FAR struct oneshot_lowerhalf_s *lower, - FAR clock_t *tick) -{ - struct timespec ts; - ONESHOT_CANCEL(lower, &ts); - *tick = clock_time2ticks_floor(&ts); - return OK; -} +/**************************************************************************** + * Name: oneshot_tick_current + * + * Description: + * Get the current system tick. + * + * Input Parameters: + * ops - The oneshot interface. + * lower - The oneshot lowerhalf data. + * + * Returned Value: + * The current system tick. + * + ****************************************************************************/ static inline_function int oneshot_tick_current(FAR struct oneshot_lowerhalf_s *lower, FAR clock_t *tick) { + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + clkcnt_t cnt = lower->ops->current(lower); + uint32_t freq = lower->frequency; + uint64_t sec = clkcnt_cnt2sec(cnt, freq); + + cnt -= sec * freq; + *tick = sec * TICK_PER_SEC + clkcnt_delta_cnt2tick(cnt, freq); +#else struct timespec ts; /* Some timer drivers may not have current() function. @@ -311,9 +473,45 @@ int oneshot_tick_current(FAR struct oneshot_lowerhalf_s *lower, DEBUGASSERT(lower->ops->current); - ONESHOT_CURRENT(lower, &ts); + ret = lower->ops->current(lower, &ts); + *tick = clock_time2ticks_floor(&ts); +#endif + return ret; +} + +/**************************************************************************** + * Name: oneshot_tick_cancel + * + * Description: + * Cancel the timer. + * + * Input Parameters: + * ops - The oneshot interface. + * lower - The oneshot lowerhalf data. + * + * Returned Value: + * The current system tick. + * + ****************************************************************************/ + +static inline_function +int oneshot_tick_cancel(FAR struct oneshot_lowerhalf_s *lower, + FAR clock_t *tick) +{ + int ret = OK; +#ifdef CONFIG_ONESHOT_COUNT + lower->ops->cancel(lower); + oneshot_tick_current(lower, tick); +#else + struct timespec ts; + + ret = lower->ops->cancel(lower, &ts); + + /* Converting timespec to ticks may overflow. */ + *tick = clock_time2ticks_floor(&ts); - return OK; +#endif + return ret; } static inline_function
