aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2017-03-31 14:26:29 -0400
committerKevin O'Connor <kevin@koconnor.net>2017-03-31 14:36:57 -0400
commita1c61563a0312c9c9f7c050e4a7588537585e49a (patch)
treeaa4bdf4f647abbe9c6b5e979d5c5d73ef0fc13c5 /src
parentaa0f1aaeb2292dd021f62b7ac9ab8e4a936918d4 (diff)
downloadkutter-a1c61563a0312c9c9f7c050e4a7588537585e49a.tar.gz
kutter-a1c61563a0312c9c9f7c050e4a7588537585e49a.tar.xz
kutter-a1c61563a0312c9c9f7c050e4a7588537585e49a.zip
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>
Diffstat (limited to 'src')
-rw-r--r--src/avr/timer.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/src/avr/timer.c b/src/avr/timer.c
index ac7509ed..c0a04624 100644
--- a/src/avr/timer.c
+++ b/src/avr/timer.c
@@ -70,6 +70,17 @@ timer_repeat_set(uint16_t next)
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
timer_init(void)
{
@@ -85,8 +96,13 @@ timer_init(void)
TCCR1A = 0;
// Normal Mode
TCCR1B = 1<<CS10;
+ // Setup for first irq
+ irqstatus_t flag = irq_save();
+ timer_reset();
+ TIFR1 = 1<<TOV1;
// enable interrupt
TIMSK1 = 1<<OCIE1A;
+ irq_restore(flag);
}
DECL_INIT(timer_init);
@@ -105,16 +121,9 @@ timer_read_time(void)
union u32_u calc;
calc.val = timer_get();
calc.hi = timer_high;
- if (likely(!(TIFR1 & (1<<TOV1)))) {
- 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)
+ if (TIFR1 & (1<<TOV1) && calc.lo < 0x8000)
calc.hi++;
+ irq_restore(flag);
return calc.val;
}
@@ -122,7 +131,7 @@ timer_read_time(void)
void
timer_periodic(void)
{
- if (unlikely(TIFR1 & (1<<TOV1))) {
+ if (TIFR1 & (1<<TOV1)) {
// Hardware timer has overflowed - update overflow counter
TIFR1 = 1<<TOV1;
timer_high++;