Skip to content

Commit afa6148

Browse files
authored
Merge pull request #59 from visitorckw/fix-timer-drift
Fix cumulative drift in periodic timers
2 parents b4c2d10 + fff7036 commit afa6148

File tree

2 files changed

+10
-3
lines changed

2 files changed

+10
-3
lines changed

include/sys/timer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ typedef enum {
2626
typedef struct {
2727
/* Timing Parameters */
2828
uint32_t deadline_ticks; /* Expiration time in absolute system ticks */
29-
uint32_t period_ms; /* Reload period in milliseconds */
29+
uint32_t last_expected_fire_tick; /* Last calculated expected fire time for
30+
* periodic timer
31+
*/
32+
uint32_t period_ms; /* Reload period in milliseconds */
3033

3134
/* Timer Identification and State */
3235
uint16_t id; /* Unique handle assigned by the kernel */

kernel/timer.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,9 @@ void _timer_tick_handler(void)
251251

252252
/* Handle auto-reload timers */
253253
if (t->mode == TIMER_AUTORELOAD) {
254-
t->deadline_ticks = now + MS_TO_TICKS(t->period_ms);
254+
/* Calculate next expected fire tick to prevent cumulative error */
255+
t->last_expected_fire_tick += MS_TO_TICKS(t->period_ms);
256+
t->deadline_ticks = t->last_expected_fire_tick;
255257
timer_sorted_insert(t); /* Re-insert for next expiration */
256258
} else {
257259
t->mode = TIMER_DISABLED; /* One-shot timers are done */
@@ -305,6 +307,7 @@ int32_t mo_timer_create(void *(*callback)(void *arg),
305307
t->arg = arg;
306308
t->period_ms = period_ms;
307309
t->deadline_ticks = 0;
310+
t->last_expected_fire_tick = 0;
308311
t->mode = TIMER_DISABLED;
309312
t->_reserved = 0;
310313

@@ -387,7 +390,8 @@ int32_t mo_timer_start(uint16_t id, uint8_t mode)
387390

388391
/* Configure and start timer */
389392
t->mode = mode;
390-
t->deadline_ticks = mo_ticks() + MS_TO_TICKS(t->period_ms);
393+
t->last_expected_fire_tick = mo_ticks() + MS_TO_TICKS(t->period_ms);
394+
t->deadline_ticks = t->last_expected_fire_tick;
391395

392396
if (unlikely(timer_sorted_insert(t) != ERR_OK)) {
393397
t->mode = TIMER_DISABLED;

0 commit comments

Comments
 (0)