X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fdrv%2Ftimer.c;h=a64a839ca76ea5415b5f488c3edaefd0695e10cd;hb=a5b1dc3c2884ee2160c6fee43e4a34b83453b87f;hp=4ace035cdac9875ba5df10119a7892e34c70fac9;hpb=32d1445272120a254d77ce8d1af1f527da7a2c17;p=bertos.git diff --git a/bertos/drv/timer.c b/bertos/drv/timer.c index 4ace035c..a64a839c 100644 --- a/bertos/drv/timer.c +++ b/bertos/drv/timer.c @@ -52,7 +52,7 @@ #include #include // cpu_relax() -#include // proc_decQuantun() +#include // proc_decQuantun() /* * Include platform-specific binding code if we're hosted. @@ -127,10 +127,6 @@ INLINE void timer_addToList(Timer *timer, List *queue) ASSERT(timer->magic != TIMER_MAGIC_ACTIVE); DB(timer->magic = TIMER_MAGIC_ACTIVE;) - - /* Calculate expiration time for this timer */ - timer->tick = _clock + timer->_delay; - /* * Search for the first node whose expiration time is * greater than the timer we want to add. @@ -162,7 +158,12 @@ INLINE void timer_addToList(Timer *timer, List *queue) */ void timer_add(Timer *timer) { - ATOMIC(timer_addToList(timer, &timers_queue)); + ATOMIC( + /* Calculate expiration time for this timer */ + timer->tick = _clock + timer->_delay; + + timer_addToList(timer, &timers_queue); + ); } /** @@ -212,9 +213,18 @@ INLINE void timer_poll(List *queue) */ void synctimer_add(Timer *timer, List *queue) { + timer->tick = timer_clock() + timer->_delay; + timer_addToList(timer, queue); } +void synctimer_readd(Timer *timer, List *queue) +{ + timer->tick += timer->_delay; + timer_addToList(timer, queue); +} + + /** * Simple synchronous timer based scheduler polling routine. * @@ -252,7 +262,7 @@ void timer_delayTicks(ticks_t delay) #if CONFIG_KERN_SIGNALS Timer t; - + DB(t.magic = TIMER_MAGIC_INACTIVE;) if (proc_preemptAllowed()) { ASSERT(!sig_check(SIG_SINGLE)); @@ -286,15 +296,30 @@ void timer_busyWait(hptime_t delay) hptime_t now, prev = timer_hw_hpread(); hptime_t delta; - for(;;) + for (;;) { now = timer_hw_hpread(); /* - * We rely on hptime_t being unsigned here to - * reduce the modulo to an AND in the common - * case of TIMER_HW_CNT. + * The timer counter may wrap here and "prev" can become + * greater than "now". So, be sure to always evaluate a + * coherent timer difference: + * + * 0 prev now TIMER_HW_CNT + * |_____|_______________|_____| + * ^^^^^^^^^^^^^^^ + * delta = now - prev + * + * 0 now prev TIMER_HW_CNT + * |_____|_______________|_____| + * ^^^^^ ^^^^^ + * delta = (TIMER_HW_CNT - prev) + now + * + * NOTE: TIMER_HW_CNT can be any value, not necessarily a power + * of 2. For this reason the "%" operator is not suitable for + * the generic case. */ - delta = (now - prev) % TIMER_HW_CNT; + delta = (now < prev) ? ((hptime_t)TIMER_HW_CNT - prev + now) : + (now - prev); if (delta >= delay) break; delay -= delta; @@ -345,9 +370,6 @@ DEFINE_TIMER_ISR TIMER_STROBE_ON; - /* Perform hw IRQ handling */ - timer_hw_irq(); - /* Update the master ms counter */ ++_clock; @@ -358,6 +380,9 @@ DEFINE_TIMER_ISR timer_poll(&timers_queue); #endif + /* Perform hw IRQ handling */ + timer_hw_irq(); + TIMER_STROBE_OFF; } @@ -386,17 +411,14 @@ void timer_init(void) } -#if (ARCH & ARCH_EMUL) +#if (ARCH & ARCH_EMUL) || (CPU_ARM_AT91) /** - * Stop timer (only used by emulator) + * Stop timer */ void timer_cleanup(void) { MOD_CLEANUP(timer); timer_hw_cleanup(); - - // Hmmm... apparently, the demo app does not cleanup properly - //ASSERT(LIST_EMPTY(&timers_queue)); } -#endif /* ARCH_EMUL */ +#endif