diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sam3x8e/timer.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/src/sam3x8e/timer.c b/src/sam3x8e/timer.c index 0d3728ed..667e9b65 100644 --- a/src/sam3x8e/timer.c +++ b/src/sam3x8e/timer.c @@ -30,9 +30,10 @@ timer_from_us(uint32_t us) void __visible TC0_Handler(void) { - TC0->TC_CHANNEL[0].TC_SR; // clear irq pending irq_disable(); - sched_timer_kick(); + uint32_t status = TC0->TC_CHANNEL[0].TC_SR; // read to clear irq pending + if (likely(status & TC_SR_CPAS)) + sched_timer_kick(); irq_enable(); } @@ -43,6 +44,13 @@ timer_set(uint32_t value) } static void +timer_set_clear(uint32_t value) +{ + TC0->TC_CHANNEL[0].TC_RA = value; + TC0->TC_CHANNEL[0].TC_SR; // read to clear irq pending +} + +static void timer_init(void) { TcChannel *tc = &TC0->TC_CHANNEL[0]; @@ -83,12 +91,16 @@ uint8_t timer_set_next(uint32_t next) { uint32_t cur = timer_read_time(); + if (sched_is_before(TC0->TC_CHANNEL[0].TC_RA, cur) + && !(TC0->TC_CHANNEL[0].TC_SR & TC_SR_CPAS)) + // Already processing timer irqs + try_shutdown("timer_set_next called during timer dispatch"); uint32_t mintime = cur + TIMER_MIN_TICKS; if (sched_is_before(mintime, next)) { - timer_set(next); + timer_set_clear(next); return 0; } - timer_set(mintime); + timer_set_clear(mintime); return 1; } |