aboutsummaryrefslogtreecommitdiffstats
path: root/src/avr/timer.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2017-03-21 17:49:02 -0400
committerKevin O'Connor <kevin@koconnor.net>2017-03-26 22:01:07 -0400
commit14340ac4df4c58bab4b5fc4c9e4746e33958c081 (patch)
treedef298f2c4cc048b5911aa82f5a3a597cd721e74 /src/avr/timer.c
parentefbfc2b1abe3a3070992fa4c6df7c4cd5befb386 (diff)
downloadkutter-14340ac4df4c58bab4b5fc4c9e4746e33958c081.tar.gz
kutter-14340ac4df4c58bab4b5fc4c9e4746e33958c081.tar.xz
kutter-14340ac4df4c58bab4b5fc4c9e4746e33958c081.zip
timer: Organize timer_try_set_next() with priority for repeat timers
Organize the code flow to optimize for repeat timers. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/avr/timer.c')
-rw-r--r--src/avr/timer.c45
1 files changed, 26 insertions, 19 deletions
diff --git a/src/avr/timer.c b/src/avr/timer.c
index 3818e772..7b5facca 100644
--- a/src/avr/timer.c
+++ b/src/avr/timer.c
@@ -133,32 +133,39 @@ timer_periodic(void)
uint8_t
timer_try_set_next(uint32_t target)
{
- uint16_t next = target, now = timer_get();
- int16_t diff = next - now;
- if (diff > TIMER_MIN_TRY_TICKS)
- // Schedule next timer normally.
+ 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;
+ }
+
+ if (likely(diff > TIMER_MIN_TRY_TICKS))
+ // Schedule next timer normally
goto done;
- // Next timer is in the past or near future - can't reschedule to it
- if (!(TIFR1 & (1<<OCF1B))) {
- // Can run more timers from this irq; briefly allow irqs
+ // Next timer in very near future - wait for it to be ready
+ for (;;) {
irq_enable();
- asm("nop");
+ if (unlikely(TIFR1 & (1<<OCF1B)))
+ break;
irq_disable();
-
- while (diff >= 0) {
- // Next timer is in the near future - wait for time to occur
- now = timer_get();
- irq_enable();
- diff = next - now;
- irq_disable();
- }
- return 0;
+ diff = next - timer_get();
+ if (diff < 0)
+ return 0;
}
- if (diff < (int16_t)(-timer_from_us(1000)))
- goto fail;
+force_pause:
// Too many repeat timers - force a pause so tasks aren't starved
+ irq_disable();
+ uint16_t now = timer_get();
+ if ((int16_t)(next - now) < (int16_t)(-timer_from_us(1000)))
+ goto fail;
timer_repeat_set(now + TIMER_REPEAT_TICKS);
next = now + TIMER_DEFER_REPEAT_TICKS;