diff --git a/cpu/stm32f1/periph/timer.c b/cpu/stm32f1/periph/timer.c index d2ce653bd20c9d830996783dcddb9bf7a25ffc67..0513d0350c6072c4e3a96da33ecbd2f848807600 100644 --- a/cpu/stm32f1/periph/timer.c +++ b/cpu/stm32f1/periph/timer.c @@ -220,16 +220,33 @@ int timer_clear(tim_t dev, int channel) unsigned int timer_read(tim_t dev) { + unsigned a, b; switch (dev) { #if TIMER_0_EN case TIMER_0: - return (((unsigned int)(0xffff & TIMER_0_DEV_0->CNT)) | (TIMER_0_DEV_1->CNT<<16)); - break; + /* do OR'ing two times and only use value if results are equal. + * otherwise, the lower 16bit counter could overflow while the + * upper counter is read, leading to an incorrect result. */ + do { + a = (((unsigned int)(0xffff & TIMER_0_DEV_0->CNT)) | + (TIMER_0_DEV_1->CNT<<16)); + b = (((unsigned int)(0xffff & TIMER_0_DEV_0->CNT)) | + (TIMER_0_DEV_1->CNT<<16)); + } while (a!=b); + + return a; #endif #if TIMER_1_EN case TIMER_1: - return (((unsigned int)(0xffff & TIMER_1_DEV_0->CNT)) | (TIMER_1_DEV_1->CNT<<16)); - break; + /* see above about why loop is needed */ + do { + a = (((unsigned int)(0xffff & TIMER_1_DEV_0->CNT)) | + (TIMER_1_DEV_1->CNT<<16)); + b = (((unsigned int)(0xffff & TIMER_1_DEV_0->CNT)) | + (TIMER_1_DEV_1->CNT<<16)); + } while (a!=b); + + return a; #endif case TIMER_UNDEFINED: default: diff --git a/sys/xtimer/xtimer_core.c b/sys/xtimer/xtimer_core.c index d7a57117fe5fedfdd0481c1fb07e02a158dd7315..0e1ceaf2e1696c369fc59ee6b39577a3d9be276e 100644 --- a/sys/xtimer/xtimer_core.c +++ b/sys/xtimer/xtimer_core.c @@ -170,19 +170,17 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) } timer->target = target; + timer->long_target = _long_cnt; + if (target < now) { + timer->long_target++; + } unsigned state = disableIRQ(); if ( !_this_high_period(target) ) { DEBUG("xtimer_set_absolute(): the timer doesn't fit into the low-level timer's mask.\n"); - timer->long_target = _long_cnt; _add_timer_to_long_list(&long_list_head, timer); } else { - if (!target) { - /* set long_target != 0 so _is_set() can work */ - timer->long_target = 1; - } - if (_mask(now) >= target) { DEBUG("xtimer_set_absolute(): the timer will expire in the next timer period\n"); _add_timer_to_list(&overflow_list_head, timer);