avr: Integrate timer_try_set_next() into the irq handler
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
6d05dd07f5
commit
65be6d5146
|
@ -135,40 +135,40 @@ timer_periodic(void)
|
||||||
#define TIMER_MIN_TRY_TICKS 60 // 40 ticks to exit irq; 20 ticks of progress
|
#define TIMER_MIN_TRY_TICKS 60 // 40 ticks to exit irq; 20 ticks of progress
|
||||||
#define TIMER_DEFER_REPEAT_TICKS 200
|
#define TIMER_DEFER_REPEAT_TICKS 200
|
||||||
|
|
||||||
// Set the next timer wake time (in absolute clock ticks) or return 1
|
// Hardware timer IRQ handler - dispatch software timers
|
||||||
// if the next timer is too close to schedule. Caller must disable
|
ISR(TIMER1_COMPA_vect)
|
||||||
// irqs.
|
|
||||||
static uint8_t
|
|
||||||
timer_try_set_next(unsigned int target)
|
|
||||||
{
|
{
|
||||||
uint16_t next = target;
|
uint16_t next;
|
||||||
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 in very near future - wait for it to be ready
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
irq_enable();
|
// Run the next software timer
|
||||||
if (unlikely(TIFR1 & (1<<OCF1B)))
|
next = sched_timer_dispatch();
|
||||||
break;
|
|
||||||
irq_disable();
|
int16_t diff = next - timer_get();
|
||||||
diff = next - timer_get();
|
if (likely(diff < 0)) {
|
||||||
if (diff < 0)
|
// Another timer is pending - briefly allow irqs to fire
|
||||||
return 0;
|
irq_enable();
|
||||||
|
if (unlikely(TIFR1 & (1<<OCF1B)))
|
||||||
|
// Too many repeat timers - must exit irq handler
|
||||||
|
goto force_defer;
|
||||||
|
irq_disable();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// Too many repeat timers - force a pause so tasks aren't starved
|
||||||
irq_disable();
|
irq_disable();
|
||||||
uint16_t now = timer_get();
|
uint16_t now = timer_get();
|
||||||
|
@ -179,24 +179,11 @@ force_pause:
|
||||||
|
|
||||||
done:
|
done:
|
||||||
timer_set(next);
|
timer_set(next);
|
||||||
return 1;
|
return;
|
||||||
fail:
|
fail:
|
||||||
shutdown("Rescheduled timer in the past");
|
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
|
// Periodic background task that temporarily boosts priority of
|
||||||
// timers. This helps prioritize timers when tasks are idling.
|
// timers. This helps prioritize timers when tasks are idling.
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue