hw pit: fix precision reduction to milliseconds

Due to the simplicity of the algorithm that translated from timer ticks
to time, we lost microseconds precision although the timer allows for it.

Ref #2400
This commit is contained in:
Martin Stein 2017-08-23 18:19:32 +02:00 committed by Christian Helmuth
parent 02bbb2efaf
commit 16745946e0
1 changed files with 24 additions and 1 deletions

View File

@ -64,6 +64,7 @@ Timer_driver::Timer_driver(unsigned)
/* Calculate timer frequency */
ticks_per_ms = pit_calc_timer_freq();
assert(ticks_per_ms >= 1000);
}
@ -84,7 +85,29 @@ void Timer::_start_one_shot(time_t const ticks) {
time_t Timer::_ticks_to_us(time_t const ticks) const {
return (ticks / _driver.ticks_per_ms) * 1000; }
/*
* If we would do the translation with one division and
* multiplication over the whole argument, we would loose
* microseconds granularity although the timer frequency would
* allow for such granularity. Thus, we treat the most significant
* half and the least significant half of the argument separate.
* Each half is shifted to the best bit position for the
* translation, then translated, and then shifted back.
*/
enum {
HALF_WIDTH = (sizeof(time_t) << 2),
MSB_MASK = ~0UL << HALF_WIDTH,
LSB_MASK = ~0UL >> HALF_WIDTH,
MSB_RSHIFT = 10,
LSB_LSHIFT = HALF_WIDTH - MSB_RSHIFT,
};
time_t const msb = ((((ticks & MSB_MASK) >> MSB_RSHIFT)
* 1000) / _driver.ticks_per_ms) << MSB_RSHIFT;
time_t const lsb = ((((ticks & LSB_MASK) << LSB_LSHIFT)
* 1000) / _driver.ticks_per_ms) >> LSB_LSHIFT;
return msb + lsb;
}
time_t Timer::us_to_ticks(time_t const us) const {