avr: Optimize 16bit timer upscaling
The hardware timer overflow bit can be used to optimize the conversion from 16bit timers to 32bit timers. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
a38437f378
commit
16e3dbb18c
|
@ -83,20 +83,29 @@ DECL_INIT(timer_init);
|
||||||
* 32bit timer wrappers
|
* 32bit timer wrappers
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
static uint32_t timer_last;
|
static uint16_t timer_high;
|
||||||
|
|
||||||
// Return the 32bit current time given the 16bit current time.
|
// Return the current time (in absolute clock ticks).
|
||||||
static __always_inline uint32_t
|
uint32_t
|
||||||
calc_time(uint32_t last, uint16_t cur)
|
timer_read_time(void)
|
||||||
{
|
{
|
||||||
union u32_u16_u {
|
union u32_u16_u {
|
||||||
struct { uint16_t lo, hi; };
|
struct { uint16_t lo, hi; };
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
} calc;
|
} calc;
|
||||||
calc.val = last;
|
irqstatus_t flag = irq_save();
|
||||||
if (cur < calc.lo)
|
calc.val = timer_get();
|
||||||
|
calc.hi = timer_high;
|
||||||
|
if (!(TIFR1 & (1<<TOV1))) {
|
||||||
|
irq_restore(flag);
|
||||||
|
return calc.val;
|
||||||
|
}
|
||||||
|
// Hardware timer has overflowed - update overflow counter
|
||||||
|
TIFR1 = 1<<TOV1;
|
||||||
|
timer_high = calc.hi + 1;
|
||||||
|
irq_restore(flag);
|
||||||
|
if (calc.lo < 0x8000)
|
||||||
calc.hi++;
|
calc.hi++;
|
||||||
calc.lo = cur;
|
|
||||||
return calc.val;
|
return calc.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,18 +113,11 @@ calc_time(uint32_t last, uint16_t cur)
|
||||||
void
|
void
|
||||||
timer_periodic(void)
|
timer_periodic(void)
|
||||||
{
|
{
|
||||||
timer_last = calc_time(timer_last, timer_get());
|
if (TIFR1 & (1<<TOV1)) {
|
||||||
|
// Hardware timer has overflowed - update overflow counter
|
||||||
|
TIFR1 = 1<<TOV1;
|
||||||
|
timer_high++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the current time (in absolute clock ticks).
|
|
||||||
uint32_t
|
|
||||||
timer_read_time(void)
|
|
||||||
{
|
|
||||||
irqstatus_t flag = irq_save();
|
|
||||||
uint16_t cur = timer_get();
|
|
||||||
uint32_t last = timer_last;
|
|
||||||
irq_restore(flag);
|
|
||||||
return calc_time(last, cur);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TIMER_MIN_TICKS 100
|
#define TIMER_MIN_TICKS 100
|
||||||
|
@ -126,11 +128,11 @@ timer_read_time(void)
|
||||||
uint8_t
|
uint8_t
|
||||||
timer_set_next(uint32_t next)
|
timer_set_next(uint32_t next)
|
||||||
{
|
{
|
||||||
uint16_t cur = timer_get();
|
uint32_t cur = timer_read_time();
|
||||||
if ((int16_t)(OCR1A - cur) < 0 && !(TIFR1 & (1<<OCF1A)))
|
if ((int16_t)(OCR1A - (uint16_t)cur) < 0 && !(TIFR1 & (1<<OCF1A)))
|
||||||
// Already processing timer irqs
|
// Already processing timer irqs
|
||||||
try_shutdown("timer_set_next called during timer dispatch");
|
try_shutdown("timer_set_next called during timer dispatch");
|
||||||
uint32_t mintime = calc_time(timer_last, cur + TIMER_MIN_TICKS);
|
uint32_t mintime = cur + TIMER_MIN_TICKS;
|
||||||
if (sched_is_before(mintime, next)) {
|
if (sched_is_before(mintime, next)) {
|
||||||
timer_set_clear(next);
|
timer_set_clear(next);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue