mirror of https://github.com/ARMmbed/mbed-os.git
NCS36510: Fixed drift in ticker interrupt
The NCS36510 is limited to 16bit timers. Construction of larger intervals is performed in software by counting the number of 16bit intervals that pass. Either this counting takes a bit of time, or there is a math error somewhere (maybe a long critical section?), because there is a roughly ~1us delay between when the interrupt occurs and the ticker progresses onto the next 16bit interval. This is normally a completely reasonable error, except that the error accumulates. After a while, the equeue tests find themselves with tens of milliseconds of error. To make matters worse, this error is random because of other interrupts occuring in the system, making the exact issue quite a bit difficult to track down. This fix drops the software counter in favor of just recalculating the next delay interval from the target time and value of the running timer. The running timer used to calculate the current tick is left to overflow in hardware and doesn't have this drift.pull/3779/head
parent
1f9e239a7d
commit
c0951c9035
|
@ -37,7 +37,7 @@ static int us_ticker_inited = 0;
|
|||
|
||||
static void us_timer_init(void);
|
||||
|
||||
static uint32_t us_ticker_int_counter = 0;
|
||||
static uint32_t us_ticker_target = 0;
|
||||
static volatile uint32_t msb_counter = 0;
|
||||
|
||||
void us_ticker_init(void)
|
||||
|
@ -168,20 +168,25 @@ extern void us_ticker_isr(void)
|
|||
/* Clear IRQ flag */
|
||||
TIM1REG->CLEAR = 0;
|
||||
|
||||
/* If this is a longer timer it will take multiple full hw counter cycles */
|
||||
if (us_ticker_int_counter > 0) {
|
||||
ticker_set(0xFFFF);
|
||||
us_ticker_int_counter--;
|
||||
} else {
|
||||
int32_t delta = us_ticker_target - us_ticker_read();
|
||||
if (delta <= 0) {
|
||||
TIM1REG->CONTROL.BITS.ENABLE = False;
|
||||
us_ticker_irq_handler();
|
||||
} else {
|
||||
// Clamp at max value of timer
|
||||
if (delta > 0xFFFF) {
|
||||
delta = 0xFFFF;
|
||||
}
|
||||
|
||||
ticker_set(delta);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set timer 1 ticker interrupt */
|
||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
int32_t delta = (uint32_t)timestamp - us_ticker_read();
|
||||
us_ticker_target = (uint32_t)timestamp;
|
||||
int32_t delta = us_ticker_target - us_ticker_read();
|
||||
|
||||
if (delta <= 0) {
|
||||
/* This event was in the past */
|
||||
|
@ -195,10 +200,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Calculate how much delta falls outside the 16-bit counter range. */
|
||||
/* You will have to perform a full timer overflow for each bit above */
|
||||
/* that range. */
|
||||
us_ticker_int_counter = (uint32_t)(delta >> 16);
|
||||
// Clamp at max value of timer
|
||||
if (delta > 0xFFFF) {
|
||||
delta = 0xFFFF;
|
||||
}
|
||||
|
||||
ticker_set(delta);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue