diff --git a/include/sys/timer.h b/include/sys/timer.h index afbe7514..397eb9dd 100644 --- a/include/sys/timer.h +++ b/include/sys/timer.h @@ -26,7 +26,10 @@ typedef enum { typedef struct { /* Timing Parameters */ uint32_t deadline_ticks; /* Expiration time in absolute system ticks */ - uint32_t period_ms; /* Reload period in milliseconds */ + uint32_t last_expected_fire_tick; /* Last calculated expected fire time for + * periodic timer + */ + uint32_t period_ms; /* Reload period in milliseconds */ /* Timer Identification and State */ uint16_t id; /* Unique handle assigned by the kernel */ diff --git a/kernel/timer.c b/kernel/timer.c index 8153d763..f3cc08aa 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -251,7 +251,9 @@ void _timer_tick_handler(void) /* Handle auto-reload timers */ if (t->mode == TIMER_AUTORELOAD) { - t->deadline_ticks = now + MS_TO_TICKS(t->period_ms); + /* Calculate next expected fire tick to prevent cumulative error */ + t->last_expected_fire_tick += MS_TO_TICKS(t->period_ms); + t->deadline_ticks = t->last_expected_fire_tick; timer_sorted_insert(t); /* Re-insert for next expiration */ } else { t->mode = TIMER_DISABLED; /* One-shot timers are done */ @@ -305,6 +307,7 @@ int32_t mo_timer_create(void *(*callback)(void *arg), t->arg = arg; t->period_ms = period_ms; t->deadline_ticks = 0; + t->last_expected_fire_tick = 0; t->mode = TIMER_DISABLED; t->_reserved = 0; @@ -387,7 +390,8 @@ int32_t mo_timer_start(uint16_t id, uint8_t mode) /* Configure and start timer */ t->mode = mode; - t->deadline_ticks = mo_ticks() + MS_TO_TICKS(t->period_ms); + t->last_expected_fire_tick = mo_ticks() + MS_TO_TICKS(t->period_ms); + t->deadline_ticks = t->last_expected_fire_tick; if (unlikely(timer_sorted_insert(t) != ERR_OK)) { t->mode = TIMER_DISABLED;