diff --git a/arch/arm/src/common/stm32/stm32_tickless_m3m4_v1.c b/arch/arm/src/common/stm32/stm32_tickless_m3m4_v1.c index 1e49c2a3cb3d8..fffce70928cdc 100644 --- a/arch/arm/src/common/stm32/stm32_tickless_m3m4_v1.c +++ b/arch/arm/src/common/stm32/stm32_tickless_m3m4_v1.c @@ -207,6 +207,15 @@ static inline void stm32_tickless_ackint(int channel) stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel)); } +/**************************************************************************** + * Name: stm32_tickless_trigint + ****************************************************************************/ + +static inline void stm32_tickless_trigint(int channel) +{ + stm32_putreg16(STM32_ATIM_EGR_OFFSET, 1 << channel); +} + /**************************************************************************** * Name: stm32_tickless_getint ****************************************************************************/ @@ -835,15 +844,9 @@ int up_timer_cancel(struct timespec *ts) (unsigned long)period, (unsigned long)count); #ifndef HAVE_32BIT_TICKLESS - if (count > period) - { - /* Handle rollover */ - - period += UINT16_MAX; - } - else if (count == period) + if ((int16_t)(period - count) <= 0) #else - if (count >= period) + if ((int32_t)(period - count) <= 0) #endif { /* No time remaining */ @@ -861,8 +864,13 @@ int up_timer_cancel(struct timespec *ts) * usecs = (ticks * USEC_PER_SEC) / frequency; */ - usec = (((uint64_t)(period - count)) * USEC_PER_SEC) / +#ifndef HAVE_32BIT_TICKLESS + usec = (((uint64_t)(uint16_t)(period - count)) * USEC_PER_SEC) / g_tickless.frequency; +#else + usec = (((uint64_t)(uint32_t)(period - count)) * USEC_PER_SEC) / + g_tickless.frequency; +#endif /* Return the time remaining in the correct form */ @@ -929,18 +937,35 @@ int up_timer_start(const struct timespec *ts) /* Express the delay in microseconds */ - usec = ts->tv_sec * USEC_PER_SEC + - (ts->tv_nsec / NSEC_PER_USEC); + if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) + { + period = 0; + } + else + { + usec = ts->tv_sec * USEC_PER_SEC + + (ts->tv_nsec / NSEC_PER_USEC); - /* Get the timer counter frequency and determine the number of counts need - * to achieve the requested delay. - * - * frequency = ticks / second - * ticks = seconds * frequency - * = (usecs * frequency) / USEC_PER_SEC; - */ + /* Get the timer counter frequency and determine the number of counts + * need to achieve the requested delay. + * + * frequency = ticks / second + * ticks = seconds * frequency + * = (usecs * frequency) / USEC_PER_SEC; + */ + + period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; + } + + if (period == 0) + { + stm32_tickless_enableint(g_tickless.channel); + stm32_tickless_trigint(g_tickless.channel); + g_tickless.pending = true; + leave_critical_section(flags); + return OK; + } - period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; count = STM32_TIM_GETCOUNTER(g_tickless.tch); tmrinfo("usec=%llu period=%08llx\n", usec, period); @@ -968,6 +993,24 @@ int up_timer_start(const struct timespec *ts) stm32_tickless_enableint(g_tickless.channel); g_tickless.pending = true; + + /* Check if the counter already reached or passed the compare target + * while we were configuring the registers. + */ + +#ifdef HAVE_32BIT_TICKLESS + if ((uint32_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - count) >= + (uint32_t)period) +#else + if ((uint16_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - (uint16_t)count) >= + (uint16_t)period) +#endif + { + /* Target time already elapsed; force the interrupt immediately */ + + stm32_tickless_trigint(g_tickless.channel); + } + leave_critical_section(flags); return OK; } diff --git a/arch/arm/src/stm32f7/stm32_tickless.c b/arch/arm/src/stm32f7/stm32_tickless.c index d348d93cadb66..48c2a986055e9 100644 --- a/arch/arm/src/stm32f7/stm32_tickless.c +++ b/arch/arm/src/stm32f7/stm32_tickless.c @@ -218,6 +218,15 @@ static inline void stm32_tickless_ackint(int channel) stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel)); } +/**************************************************************************** + * Name: stm32_tickless_trigint + ****************************************************************************/ + +static inline void stm32_tickless_trigint(int channel) +{ + stm32_putreg16(STM32_GTIM_EGR_OFFSET, 1 << channel); +} + /**************************************************************************** * Name: stm32_tickless_getint ****************************************************************************/ @@ -379,9 +388,9 @@ static int stm32_tickless_handler(int irq, void *context, void *arg) return OK; } +#ifdef CONFIG_SCHED_TICKLESS_ALARM /**************************************************************************** * Name: stm32_get_counter - * ****************************************************************************/ static uint64_t stm32_get_counter(void) @@ -394,6 +403,7 @@ static uint64_t stm32_get_counter(void) STM32_TIM_GETCOUNTER(g_tickless.tch); #endif } +#endif /**************************************************************************** * Public Functions @@ -877,15 +887,9 @@ int up_timer_cancel(struct timespec *ts) (unsigned long)period, (unsigned long)count); #ifndef HAVE_32BIT_TICKLESS - if (count > period) - { - /* Handle rollover */ - - period += UINT16_MAX; - } - else if (count == period) + if ((int16_t)(period - count) <= 0) #else - if (count >= period) + if ((int32_t)(period - count) <= 0) #endif { /* No time remaining */ @@ -903,8 +907,13 @@ int up_timer_cancel(struct timespec *ts) * usecs = (ticks * USEC_PER_SEC) / frequency; */ - usec = (((uint64_t)(period - count)) * USEC_PER_SEC) / +#ifndef HAVE_32BIT_TICKLESS + usec = (((uint64_t)(uint16_t)(period - count)) * USEC_PER_SEC) / g_tickless.frequency; +#else + usec = (((uint64_t)(uint32_t)(period - count)) * USEC_PER_SEC) / + g_tickless.frequency; +#endif /* Return the time remaining in the correct form */ @@ -973,18 +982,35 @@ int up_timer_start(const struct timespec *ts) /* Express the delay in microseconds */ - usec = ts->tv_sec * USEC_PER_SEC + - (ts->tv_nsec / NSEC_PER_USEC); + if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) + { + period = 0; + } + else + { + usec = ts->tv_sec * USEC_PER_SEC + + (ts->tv_nsec / NSEC_PER_USEC); - /* Get the timer counter frequency and determine the number of counts need - * to achieve the requested delay. - * - * frequency = ticks / second - * ticks = seconds * frequency - * = (usecs * frequency) / USEC_PER_SEC; - */ + /* Get the timer counter frequency and determine the number of counts + * need to achieve the requested delay. + * + * frequency = ticks / second + * ticks = seconds * frequency + * = (usecs * frequency) / USEC_PER_SEC; + */ + + period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; + } + + if (period == 0) + { + stm32_tickless_enableint(g_tickless.channel); + stm32_tickless_trigint(g_tickless.channel); + g_tickless.pending = true; + leave_critical_section(flags); + return OK; + } - period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; count = STM32_TIM_GETCOUNTER(g_tickless.tch); tmrinfo("usec=%llu period=%08llx\n", usec, period); @@ -1012,6 +1038,24 @@ int up_timer_start(const struct timespec *ts) stm32_tickless_enableint(g_tickless.channel); g_tickless.pending = true; + + /* Check if the counter already reached or passed the compare target + * while we were configuring the registers. + */ + +#ifdef HAVE_32BIT_TICKLESS + if ((uint32_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - count) >= + (uint32_t)period) +#else + if ((uint16_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - (uint16_t)count) >= + (uint16_t)period) +#endif + { + /* Target time already elapsed; force the interrupt immediately */ + + stm32_tickless_trigint(g_tickless.channel); + } + leave_critical_section(flags); return OK; } diff --git a/arch/arm/src/stm32h7/stm32_tickless.c b/arch/arm/src/stm32h7/stm32_tickless.c index 7fb140248cb55..241bf886cc583 100644 --- a/arch/arm/src/stm32h7/stm32_tickless.c +++ b/arch/arm/src/stm32h7/stm32_tickless.c @@ -205,6 +205,15 @@ static inline void stm32_tickless_ackint(int channel) stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel)); } +/**************************************************************************** + * Name: stm32_tickless_trigint + ****************************************************************************/ + +static inline void stm32_tickless_trigint(int channel) +{ + stm32_putreg16(STM32_GTIM_EGR_OFFSET, 1 << channel); +} + /**************************************************************************** * Name: stm32_tickless_getint ****************************************************************************/ @@ -366,9 +375,9 @@ static int stm32_tickless_handler(int irq, void *context, void *arg) return OK; } +#ifdef CONFIG_SCHED_TICKLESS_ALARM /**************************************************************************** * Name: stm32_get_counter - * ****************************************************************************/ static uint64_t stm32_get_counter(void) @@ -381,6 +390,7 @@ static uint64_t stm32_get_counter(void) STM32_TIM_GETCOUNTER(g_tickless.tch); #endif } +#endif /**************************************************************************** * Public Functions @@ -851,15 +861,9 @@ int up_timer_cancel(struct timespec *ts) (unsigned long)period, (unsigned long)count); #ifndef HAVE_32BIT_TICKLESS - if (count > period) - { - /* Handle rollover */ - - period += UINT16_MAX; - } - else if (count == period) + if ((int16_t)(period - count) <= 0) #else - if (count >= period) + if ((int32_t)(period - count) <= 0) #endif { /* No time remaining */ @@ -877,8 +881,13 @@ int up_timer_cancel(struct timespec *ts) * usecs = (ticks * USEC_PER_SEC) / frequency; */ - usec = (((uint64_t)(period - count)) * USEC_PER_SEC) / +#ifndef HAVE_32BIT_TICKLESS + usec = (((uint64_t)(uint16_t)(period - count)) * USEC_PER_SEC) / g_tickless.frequency; +#else + usec = (((uint64_t)(uint32_t)(period - count)) * USEC_PER_SEC) / + g_tickless.frequency; +#endif /* Return the time remaining in the correct form */ @@ -947,18 +956,35 @@ int up_timer_start(const struct timespec *ts) /* Express the delay in microseconds */ - usec = ts->tv_sec * USEC_PER_SEC + - (ts->tv_nsec / NSEC_PER_USEC); + if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) + { + period = 0; + } + else + { + usec = ts->tv_sec * USEC_PER_SEC + + (ts->tv_nsec / NSEC_PER_USEC); - /* Get the timer counter frequency and determine the number of counts need - * to achieve the requested delay. - * - * frequency = ticks / second - * ticks = seconds * frequency - * = (usecs * frequency) / USEC_PER_SEC; - */ + /* Get the timer counter frequency and determine the number of counts + * need to achieve the requested delay. + * + * frequency = ticks / second + * ticks = seconds * frequency + * = (usecs * frequency) / USEC_PER_SEC; + */ + + period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; + } + + if (period == 0) + { + stm32_tickless_enableint(g_tickless.channel); + stm32_tickless_trigint(g_tickless.channel); + g_tickless.pending = true; + leave_critical_section(flags); + return OK; + } - period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; count = STM32_TIM_GETCOUNTER(g_tickless.tch); tmrinfo("usec=%llu period=%08llx\n", usec, period); @@ -986,6 +1012,24 @@ int up_timer_start(const struct timespec *ts) stm32_tickless_enableint(g_tickless.channel); g_tickless.pending = true; + + /* Check if the counter already reached or passed the compare target + * while we were configuring the registers. + */ + +#ifdef HAVE_32BIT_TICKLESS + if ((uint32_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - count) >= + (uint32_t)period) +#else + if ((uint16_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - (uint16_t)count) >= + (uint16_t)period) +#endif + { + /* Target time already elapsed; force the interrupt immediately */ + + stm32_tickless_trigint(g_tickless.channel); + } + leave_critical_section(flags); return OK; } diff --git a/arch/arm/src/stm32wb/stm32wb_tickless.c b/arch/arm/src/stm32wb/stm32wb_tickless.c index a8ae84dc54e3d..801c6cdea9e70 100644 --- a/arch/arm/src/stm32wb/stm32wb_tickless.c +++ b/arch/arm/src/stm32wb/stm32wb_tickless.c @@ -187,6 +187,15 @@ static inline void stm32_tickless_ackint(int channel) stm32_putreg16(STM32_TIM_SR_OFFSET, ~(1 << channel)); } +/**************************************************************************** + * Name: stm32_tickless_trigint + ****************************************************************************/ + +static inline void stm32_tickless_trigint(int channel) +{ + stm32_putreg16(STM32_TIM_EGR_OFFSET, 1 << channel); +} + /**************************************************************************** * Name: stm32_tickless_getint ****************************************************************************/ @@ -701,15 +710,9 @@ int up_timer_cancel(struct timespec *ts) (unsigned long)period, (unsigned long)count); #ifndef HAVE_32BIT_TICKLESS - if (count > period) - { - /* Handle rollover */ - - period += UINT16_MAX; - } - else if (count == period) + if ((int16_t)(period - count) <= 0) #else - if (count >= period) + if ((int32_t)(period - count) <= 0) #endif { /* No time remaining */ @@ -727,8 +730,13 @@ int up_timer_cancel(struct timespec *ts) * usecs = (ticks * USEC_PER_SEC) / frequency; */ - usec = (((uint64_t)(period - count)) * USEC_PER_SEC) / +#ifndef HAVE_32BIT_TICKLESS + usec = (((uint64_t)(uint16_t)(period - count)) * USEC_PER_SEC) / g_tickless.frequency; +#else + usec = (((uint64_t)(uint32_t)(period - count)) * USEC_PER_SEC) / + g_tickless.frequency; +#endif /* Return the time remaining in the correct form */ @@ -795,18 +803,35 @@ int up_timer_start(const struct timespec *ts) /* Express the delay in microseconds */ - usec = ts->tv_sec * USEC_PER_SEC + - (ts->tv_nsec / NSEC_PER_USEC); + if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) + { + period = 0; + } + else + { + usec = ts->tv_sec * USEC_PER_SEC + + (ts->tv_nsec / NSEC_PER_USEC); - /* Get the timer counter frequency and determine the number of counts need - * to achieve the requested delay. - * - * frequency = ticks / second - * ticks = seconds * frequency - * = (usecs * frequency) / USEC_PER_SEC; - */ + /* Get the timer counter frequency and determine the number of counts + * need to achieve the requested delay. + * + * frequency = ticks / second + * ticks = seconds * frequency + * = (usecs * frequency) / USEC_PER_SEC; + */ + + period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; + } + + if (period == 0) + { + stm32_tickless_enableint(g_tickless.channel); + stm32_tickless_trigint(g_tickless.channel); + g_tickless.pending = true; + leave_critical_section(flags); + return OK; + } - period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC; count = STM32_TIM_GETCOUNTER(g_tickless.tch); tmrinfo("usec=%llu period=%08llx\n", usec, period); @@ -814,6 +839,7 @@ int up_timer_start(const struct timespec *ts) /* Set interval compare value. Rollover is fine, * channel will trigger on the next period. */ + #ifdef HAVE_32BIT_TICKLESS DEBUGASSERT(period <= UINT32_MAX); g_tickless.period = (uint32_t)(period + count); @@ -833,6 +859,24 @@ int up_timer_start(const struct timespec *ts) stm32_tickless_enableint(g_tickless.channel); g_tickless.pending = true; + + /* Check if the counter already reached or passed the compare target + * while we were configuring the registers. + */ + +#ifdef HAVE_32BIT_TICKLESS + if ((uint32_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - count) >= + (uint32_t)period) +#else + if ((uint16_t)(STM32_TIM_GETCOUNTER(g_tickless.tch) - (uint16_t)count) >= + (uint16_t)period) +#endif + { + /* Target time already elapsed; force the interrupt immediately */ + + stm32_tickless_trigint(g_tickless.channel); + } + leave_critical_section(flags); return OK; } diff --git a/sched/clock/clock_timekeeping.c b/sched/clock/clock_timekeeping.c index 4d5a48b684c87..9afe11494b111 100644 --- a/sched/clock/clock_timekeeping.c +++ b/sched/clock/clock_timekeeping.c @@ -39,20 +39,25 @@ #include #include "clock/clock.h" +#include "clock/clock_timekeeping.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define NTP_MAX_ADJUST 500 +#ifdef CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM +# define NTP_MAX_ADJUST CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM +#else +# define NTP_MAX_ADJUST 500 +#endif /**************************************************************************** * Private Data ****************************************************************************/ static struct timespec g_clock_wall_time; -static uint64_t g_clock_last_counter; -static uint64_t g_clock_mask; +static clock_t g_clock_last_counter; +static clock_t g_clock_mask; static long g_clock_adjust; static spinlock_t g_clock_lock = SP_UNLOCKED; @@ -68,8 +73,8 @@ static int clock_get_current_time(FAR struct timespec *ts, FAR struct timespec *base) { irqstate_t flags; - uint64_t counter; - uint64_t offset; + clock_t counter; + clock_t offset; uint64_t nsec; time_t sec; int ret; @@ -112,6 +117,7 @@ static int clock_get_current_time(FAR struct timespec *ts, int clock_timekeeping_get_wall_time(FAR struct timespec *ts) { + clock_update_wall_time(); return clock_get_current_time(ts, &g_clock_wall_time); } @@ -122,7 +128,7 @@ int clock_timekeeping_get_wall_time(FAR struct timespec *ts) int clock_timekeeping_set_wall_time(FAR const struct timespec *ts) { irqstate_t flags; - uint64_t counter; + clock_t counter; int ret; flags = spin_lock_irqsave(&g_clock_lock); @@ -214,8 +220,8 @@ int adjtime(FAR const struct timeval *delta, FAR struct timeval *olddelta) void clock_update_wall_time(void) { irqstate_t flags; - uint64_t counter; - uint64_t offset; + clock_t counter; + clock_t offset; int64_t nsec; time_t sec; int ret; @@ -261,8 +267,8 @@ void clock_update_wall_time(void) adjust = -limit; } - nsec += adjust * NSEC_PER_USEC; g_clock_adjust -= adjust; + nsec += adjust * NSEC_PER_USEC; while (nsec < 0) { diff --git a/sched/sched/sched_processtickless.c b/sched/sched/sched_processtickless.c index 1111dd0349b73..c91eda9aa5fae 100644 --- a/sched/sched/sched_processtickless.c +++ b/sched/sched/sched_processtickless.c @@ -354,6 +354,12 @@ void nxsched_process_timer(void) flags = enter_critical_section(); +#ifdef CONFIG_CLOCK_TIMEKEEPING + /* Process wall time */ + + clock_update_wall_time(); +#endif + /* Do not move the up_timer_gettick out of the critical section, * it will violate the invariant that the g_timer_tick should be monotonic. */