avr: Fix bug causing timer_read_time() to not be in sync with scheduler
Commit 16e3dbb1
changed the avr implementation of timer_read_time().
Unfortunately, it raised the possibility for timer_read_time() to be
out of sync with the scheduler's understanding of the current time.
In particular, it was common for the timer irq to overflow the 16bit
hardware counter once at startup, and this would lead to
timer_read_time() always returning a time ~4ms ahead of the scheduler
on 16Mhz chips. This resulted in "Move queue empty" errors.
To resolve this issue, only increment timer_high from timer_periodic()
and make sure the timer irqs start immediately after timer_init().
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
aa0f1aaeb2
commit
a1c61563a0
|
@ -70,6 +70,17 @@ timer_repeat_set(uint16_t next)
|
||||||
TIFR1 = 1<<OCF1B;
|
TIFR1 = 1<<OCF1B;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the timer - clear settings and dispatch next timer immediately
|
||||||
|
static void
|
||||||
|
timer_reset(void)
|
||||||
|
{
|
||||||
|
uint16_t now = timer_get();
|
||||||
|
timer_set(now + 50);
|
||||||
|
TIFR1 = 1<<OCF1A;
|
||||||
|
timer_repeat_set(now + 50);
|
||||||
|
}
|
||||||
|
DECL_SHUTDOWN(timer_reset);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
timer_init(void)
|
timer_init(void)
|
||||||
{
|
{
|
||||||
|
@ -85,8 +96,13 @@ timer_init(void)
|
||||||
TCCR1A = 0;
|
TCCR1A = 0;
|
||||||
// Normal Mode
|
// Normal Mode
|
||||||
TCCR1B = 1<<CS10;
|
TCCR1B = 1<<CS10;
|
||||||
|
// Setup for first irq
|
||||||
|
irqstatus_t flag = irq_save();
|
||||||
|
timer_reset();
|
||||||
|
TIFR1 = 1<<TOV1;
|
||||||
// enable interrupt
|
// enable interrupt
|
||||||
TIMSK1 = 1<<OCIE1A;
|
TIMSK1 = 1<<OCIE1A;
|
||||||
|
irq_restore(flag);
|
||||||
}
|
}
|
||||||
DECL_INIT(timer_init);
|
DECL_INIT(timer_init);
|
||||||
|
|
||||||
|
@ -105,16 +121,9 @@ timer_read_time(void)
|
||||||
union u32_u calc;
|
union u32_u calc;
|
||||||
calc.val = timer_get();
|
calc.val = timer_get();
|
||||||
calc.hi = timer_high;
|
calc.hi = timer_high;
|
||||||
if (likely(!(TIFR1 & (1<<TOV1)))) {
|
if (TIFR1 & (1<<TOV1) && calc.lo < 0x8000)
|
||||||
irq_restore(flag);
|
|
||||||
return calc.val;
|
|
||||||
}
|
|
||||||
// Hardware timer has overflowed - update overflow counter
|
|
||||||
TIFR1 = 1<<TOV1;
|
|
||||||
timer_high = calc.hi + 1;
|
|
||||||
irq_restore(flag);
|
|
||||||
if (calc.lo < 0x8000)
|
|
||||||
calc.hi++;
|
calc.hi++;
|
||||||
|
irq_restore(flag);
|
||||||
return calc.val;
|
return calc.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +131,7 @@ timer_read_time(void)
|
||||||
void
|
void
|
||||||
timer_periodic(void)
|
timer_periodic(void)
|
||||||
{
|
{
|
||||||
if (unlikely(TIFR1 & (1<<TOV1))) {
|
if (TIFR1 & (1<<TOV1)) {
|
||||||
// Hardware timer has overflowed - update overflow counter
|
// Hardware timer has overflowed - update overflow counter
|
||||||
TIFR1 = 1<<TOV1;
|
TIFR1 = 1<<TOV1;
|
||||||
timer_high++;
|
timer_high++;
|
||||||
|
|
Loading…
Reference in New Issue