Skip to content

Commit c0951c9

Browse files
committed
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.
1 parent 1f9e239 commit c0951c9

File tree

1 file changed

+16
-11
lines changed

1 file changed

+16
-11
lines changed

targets/TARGET_ONSEMI/TARGET_NCS36510/ncs36510_us_ticker_api.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static int us_ticker_inited = 0;
3737

3838
static void us_timer_init(void);
3939

40-
static uint32_t us_ticker_int_counter = 0;
40+
static uint32_t us_ticker_target = 0;
4141
static volatile uint32_t msb_counter = 0;
4242

4343
void us_ticker_init(void)
@@ -168,20 +168,25 @@ extern void us_ticker_isr(void)
168168
/* Clear IRQ flag */
169169
TIM1REG->CLEAR = 0;
170170

171-
/* If this is a longer timer it will take multiple full hw counter cycles */
172-
if (us_ticker_int_counter > 0) {
173-
ticker_set(0xFFFF);
174-
us_ticker_int_counter--;
175-
} else {
171+
int32_t delta = us_ticker_target - us_ticker_read();
172+
if (delta <= 0) {
176173
TIM1REG->CONTROL.BITS.ENABLE = False;
177174
us_ticker_irq_handler();
175+
} else {
176+
// Clamp at max value of timer
177+
if (delta > 0xFFFF) {
178+
delta = 0xFFFF;
179+
}
180+
181+
ticker_set(delta);
178182
}
179183
}
180184

181185
/* Set timer 1 ticker interrupt */
182186
void us_ticker_set_interrupt(timestamp_t timestamp)
183187
{
184-
int32_t delta = (uint32_t)timestamp - us_ticker_read();
188+
us_ticker_target = (uint32_t)timestamp;
189+
int32_t delta = us_ticker_target - us_ticker_read();
185190

186191
if (delta <= 0) {
187192
/* This event was in the past */
@@ -195,10 +200,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
195200
return;
196201
}
197202

198-
/* Calculate how much delta falls outside the 16-bit counter range. */
199-
/* You will have to perform a full timer overflow for each bit above */
200-
/* that range. */
201-
us_ticker_int_counter = (uint32_t)(delta >> 16);
203+
// Clamp at max value of timer
204+
if (delta > 0xFFFF) {
205+
delta = 0xFFFF;
206+
}
202207

203208
ticker_set(delta);
204209
}

0 commit comments

Comments
 (0)