kinetis: lptmr reload instead of spinning
Spinning for the correct time has the side effect that it may cause infinite recursion if the callback function calls timer_set. timer_set->callback->...->timer_set->callback->...->timer_set-> infinity In theory, the drawback is that the callback for very short timeouts (<2 lptmr ticks) may be delayed up to 2 lptmr ticks (61 µs) In practice however, tests performed using tests/bench_timers shows that this change only affects the accuracy of the timer target when timer_set is called with a timeout of 0, which results in a delay of 30 µs.
This commit is contained in:
parent
b709e63581
commit
fa3b9168a0
@ -379,38 +379,26 @@ static inline uint16_t lptmr_read(uint8_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reload the timer with the given timeout, or spin if timeout is too small
|
* @brief Reload the timer with the given timeout
|
||||||
*
|
*
|
||||||
* @pre IRQs masked, timer running
|
* @pre IRQs masked, timer running
|
||||||
*/
|
*/
|
||||||
static inline void lptmr_reload_or_spin(uint8_t dev, uint16_t timeout)
|
static inline void lptmr_reload(uint8_t dev, uint16_t timeout)
|
||||||
{
|
{
|
||||||
LPTMR_Type *hw = lptmr_config[dev].dev;
|
LPTMR_Type *hw = lptmr_config[dev].dev;
|
||||||
/* Disable timer and set target, 1 to 2 ticks will be dropped by the
|
/* Disable timer and set target, 1 to 2 ticks will be dropped by the
|
||||||
* hardware during the disable-enable cycle */
|
* hardware during the disable-enable cycle */
|
||||||
/* Disable the timer interrupt first */
|
/* Disable the timer interrupt first */
|
||||||
hw->CSR = LPTMR_CSR_TEN_MASK | LPTMR_CSR_TFC_MASK;
|
hw->CSR = LPTMR_CSR_TEN_MASK | LPTMR_CSR_TFC_MASK;
|
||||||
if (timeout <= LPTMR_RELOAD_OVERHEAD) {
|
if (timeout >= LPTMR_RELOAD_OVERHEAD) {
|
||||||
/* we spin if the timeout is too short to reload the timer */
|
timeout -= LPTMR_RELOAD_OVERHEAD;
|
||||||
hw->CNR = 0;
|
|
||||||
uint16_t cnr_begin = hw->CNR;
|
|
||||||
while ((hw->CNR - cnr_begin) <= timeout) {
|
|
||||||
hw->CNR = 0;
|
|
||||||
}
|
|
||||||
/* Emulate IRQ handler behaviour */
|
|
||||||
lptmr[dev].running = 0;
|
|
||||||
if (lptmr[dev].isr_ctx.cb != NULL) {
|
|
||||||
lptmr[dev].isr_ctx.cb(lptmr[dev].isr_ctx.arg, 0);
|
|
||||||
}
|
|
||||||
thread_yield_higher();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
/* Update reference */
|
/* Update reference */
|
||||||
hw->CNR = 0;
|
hw->CNR = 0;
|
||||||
lptmr[dev].cnr += hw->CNR + LPTMR_RELOAD_OVERHEAD;
|
lptmr[dev].cnr += hw->CNR + LPTMR_RELOAD_OVERHEAD;
|
||||||
/* Disable timer */
|
/* Disable timer */
|
||||||
hw->CSR = 0;
|
hw->CSR = 0;
|
||||||
hw->CMR = timeout - LPTMR_RELOAD_OVERHEAD;
|
hw->CMR = timeout;
|
||||||
/* Enable timer and IRQ */
|
/* Enable timer and IRQ */
|
||||||
hw->CSR = LPTMR_CSR_TEN_MASK | LPTMR_CSR_TFC_MASK | LPTMR_CSR_TIE_MASK;
|
hw->CSR = LPTMR_CSR_TEN_MASK | LPTMR_CSR_TFC_MASK | LPTMR_CSR_TIE_MASK;
|
||||||
}
|
}
|
||||||
@ -431,7 +419,7 @@ static inline int lptmr_set(uint8_t dev, uint16_t timeout)
|
|||||||
lptmr[dev].cmr = 0;
|
lptmr[dev].cmr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hw->CSR & LPTMR_CSR_TCF_MASK) {
|
else if ((timeout > 0) && (hw->CSR & LPTMR_CSR_TCF_MASK)) {
|
||||||
/* TCF is set, safe to update CMR live */
|
/* TCF is set, safe to update CMR live */
|
||||||
hw->CNR = 0;
|
hw->CNR = 0;
|
||||||
hw->CMR = timeout + hw->CNR;
|
hw->CMR = timeout + hw->CNR;
|
||||||
@ -442,7 +430,7 @@ static inline int lptmr_set(uint8_t dev, uint16_t timeout)
|
|||||||
hw->CSR = LPTMR_CSR_TEN_MASK | LPTMR_CSR_TFC_MASK | LPTMR_CSR_TIE_MASK;
|
hw->CSR = LPTMR_CSR_TEN_MASK | LPTMR_CSR_TFC_MASK | LPTMR_CSR_TIE_MASK;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lptmr_reload_or_spin(dev, timeout);
|
lptmr_reload(dev, timeout);
|
||||||
}
|
}
|
||||||
irq_restore(mask);
|
irq_restore(mask);
|
||||||
return 1;
|
return 1;
|
||||||
@ -476,7 +464,7 @@ static inline int lptmr_set_absolute(uint8_t dev, uint16_t target)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uint16_t timeout = target - lptmr_read(dev);
|
uint16_t timeout = target - lptmr_read(dev);
|
||||||
lptmr_reload_or_spin(dev, timeout);
|
lptmr_reload(dev, timeout);
|
||||||
}
|
}
|
||||||
irq_restore(mask);
|
irq_restore(mask);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user