diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2017-03-28 10:53:19 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2017-03-30 11:24:44 -0400 |
commit | 65be6d514650f579621132ec8fd27da3541a3a37 (patch) | |
tree | 16e1d38a1da7be462baf7e1402666396b3dba353 /src/avr | |
parent | 6d05dd07f59ef21dc81a299e865cdee1fc1d3f8e (diff) | |
download | kutter-65be6d514650f579621132ec8fd27da3541a3a37.tar.gz kutter-65be6d514650f579621132ec8fd27da3541a3a37.tar.xz kutter-65be6d514650f579621132ec8fd27da3541a3a37.zip |
avr: Integrate timer_try_set_next() into the irq handler
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/avr')
-rw-r--r-- | src/avr/timer.c | 73 |
1 files changed, 30 insertions, 43 deletions
diff --git a/src/avr/timer.c b/src/avr/timer.c index f8686998..ac7509ed 100644 --- a/src/avr/timer.c +++ b/src/avr/timer.c @@ -135,40 +135,40 @@ timer_periodic(void) #define TIMER_MIN_TRY_TICKS 60 // 40 ticks to exit irq; 20 ticks of progress #define TIMER_DEFER_REPEAT_TICKS 200 -// Set the next timer wake time (in absolute clock ticks) or return 1 -// if the next timer is too close to schedule. Caller must disable -// irqs. -static uint8_t -timer_try_set_next(unsigned int target) +// Hardware timer IRQ handler - dispatch software timers +ISR(TIMER1_COMPA_vect) { - uint16_t next = target; - int16_t diff = next - timer_get(); - if (likely(diff < 0)) { - // Another timer is pending - briefly allow irqs to fire - irq_enable(); - if (unlikely(TIFR1 & (1<<OCF1B))) - // Too many repeat timers - must exit irq handler - goto force_pause; - irq_disable(); - return 0; - } + uint16_t next; + for (;;) { + // Run the next software timer + next = sched_timer_dispatch(); - if (likely(diff > TIMER_MIN_TRY_TICKS)) - // Schedule next timer normally - goto done; + int16_t diff = next - timer_get(); + if (likely(diff < 0)) { + // Another timer is pending - briefly allow irqs to fire + irq_enable(); + if (unlikely(TIFR1 & (1<<OCF1B))) + // Too many repeat timers - must exit irq handler + goto force_defer; + irq_disable(); + continue; + } - // Next timer in very near future - wait for it to be ready - for (;;) { - irq_enable(); - if (unlikely(TIFR1 & (1<<OCF1B))) - break; - irq_disable(); - diff = next - timer_get(); - if (diff < 0) - return 0; + if (likely(diff > TIMER_MIN_TRY_TICKS)) + // Schedule next timer normally + goto done; + + // Next timer in very near future - wait for it to be ready + do { + irq_enable(); + if (unlikely(TIFR1 & (1<<OCF1B))) + goto force_defer; + irq_disable(); + diff = next - timer_get(); + } while (diff >= 0); } -force_pause: +force_defer: // Too many repeat timers - force a pause so tasks aren't starved irq_disable(); uint16_t now = timer_get(); @@ -179,24 +179,11 @@ force_pause: done: timer_set(next); - return 1; + return; fail: shutdown("Rescheduled timer in the past"); } -// Harware OCR1A interrupt handler -ISR(TIMER1_COMPA_vect) -{ - for (;;) { - uint16_t next_waketime = sched_timer_dispatch(); - - // Schedule next timer event (or run next timer if it's ready) - uint8_t res = timer_try_set_next(next_waketime); - if (res) - break; - } -} - // Periodic background task that temporarily boosts priority of // timers. This helps prioritize timers when tasks are idling. static void |