X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fdrv%2Ftimer.c;h=e3043da49a7014f5294a138081d5825dc9cff8e6;hb=6aebe0e6d7a5be5aacda0b39d86b4a9b421e247c;hp=d380e5f1d458de07e0342281cbc84a934c80fdb2;hpb=f35b6066ecdeffcc8998dd566b5246bdcf43c548;p=bertos.git diff --git a/bertos/drv/timer.c b/bertos/drv/timer.c index d380e5f1..e3043da4 100644 --- a/bertos/drv/timer.c +++ b/bertos/drv/timer.c @@ -252,7 +252,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 +286,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; @@ -357,7 +372,7 @@ DEFINE_TIMER_ISR /* Perform hw IRQ handling */ timer_hw_irq(); - + TIMER_STROBE_OFF; }