Re: How to overcome timer delay


Benjamin Walsh <benjamin.walsh@...>
 

[..snip..]

void main(void)
{
struct k_timer my_timer;

printk("Hello World! %s\n", CONFIG_ARCH);
k_timer_init(&my_timer, timer_handler, NULL);
t = k_uptime_get_32();
while (1) {
k_timer_start(&my_timer, INTERVAL, K_FOREVER);
k_timer_status_sync(&my_timer);
}
}
[..snip..]

So, although increasing it improves the delay, there is a limit. And
for the TICKS_PER_SEC as high as 10000, there is still 100ms delay
over 1000 counts (10%). I think that in practice a mechanism to
compensate the delay to make it a more precise. Is there any better
way?
For your case, that is what I was saying above: if you set the tick rate
to 1000, and you ask for a delay of 1ms, this means at least 1ms, so the
system will wait for 2 ticks (the partial current one + the next one),
so it will wait for around 2ms. That is with the system clock timer,
which has a finite granularity.

If you want more precision, I would look if your board has a second
timer that your application could take ownership of so that you could
program it to fire periodically every 2ms.
Thank you so much for the explanations, Ben.
Well, that was an in-depth explanation of what is happening internally,
but I focused too much on what your code was doing that I kinda
overlooked a better way of doing what you were trying to do. :-/

Instead of stopping and starting the timer with a <duration> of 1ms and
<period> of 0 every iteration, you should just use the periodic feature
of the timer ! If you want it to fire every 2ms, do this:

k_timer_start(&my_timer, 2, 2);
while (1) {
k_timer_status_sync(&my_timer);
}

The <period> value is not aligned on the next tick boundary, since when
the timer is added back to the timeout queue, this happens in the
timer's timeout's expiration handler, which is called when already
aligned on a tick boundary. Thus, the value for the <duration> parameter
of k_timer_start when converted to ticks _will be_ pushed to the next
tick passed the requested duration, while the value for the <period>
parameter when converted to ticks _will not be_ pushed to the next tick.
Look in timer.c:_timer_expiration_handler():

/*
* if the timer is periodic, start it again; don't add _TICK_ALIGN
* since we're already aligned to a tick boundary
*/
if (timer->period > 0) {
key = irq_lock();
_add_timeout(NULL, &timer->timeout, &timer->wait_q,
timer->period);
irq_unlock(key);
}

So, with my example code above, the timer will thus fire in
2.<something> ms the first time, and at fixed interval every 2ms all
subsequent times. If you want the timer to fire within 2m the first
time, call timer start with a <duration> of 1ms instead, like this:

k_timer_start(&my_timer, 1, 2);

Hope this helps,
Ben

Join devel@lists.zephyrproject.org to automatically receive all group messages.