Skip to content

Commit

Permalink
drivers: nrf_rtc_timer: Fix handling of COMPARE events in set_alarm()
Browse files Browse the repository at this point in the history
This is a follow-up to commits cf871ae
and 205e684.

It turns out that the current implementation of the nrf_rtc_timer may
still fail to properly handle a timeout if that timeout is set in very
specific conditions - when a previously set timeout is about to expire.
When that happens, the new timeout is handled 512 seconds later (when
the system timer overflows) than it should be.

A recently added nrf_rtc_timer test case (test_tight_rescheduling)
exposes this problem and this commit fixes it by adding examination
of COMPARE events that appear during setting of the CC register value
for a given timeout.

Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
  • Loading branch information
anangl authored and carlescufi committed Feb 14, 2023
1 parent d6ba49e commit 31c11a5
Showing 1 changed file with 21 additions and 6 deletions.
27 changes: 21 additions & 6 deletions drivers/timer/nrf_rtc_timer.c
Expand Up @@ -280,13 +280,28 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
* Increase the CC value by a larger number of cycles in each
* trial to avoid spending too much time in this loop if it
* continuously gets interrupted and delayed by something.
* But if the COMPARE event turns out to be already generated,
* there is obviously no need to continue the loop.
*/
if ((counter_sub(cc_val, now + MIN_CYCLES_FROM_NOW) >
(COUNTER_HALF_SPAN - MIN_CYCLES_FROM_NOW))
&&
!event_check(chan)) {
if (counter_sub(cc_val, now + MIN_CYCLES_FROM_NOW) >
(COUNTER_HALF_SPAN - MIN_CYCLES_FROM_NOW)) {
/* If the COMPARE event turns out to be already
* generated, check if the loop can be finished.
*/
if (event_check(chan)) {
/* If the current counter value has not yet
* reached the requested CC value, the event
* must come from the previously set CC value
* (the alarm is apparently rescheduled).
* The event needs to be cleared then and the
* loop needs to be continued.
*/
now = counter();
if (counter_sub(now, req_cc) > COUNTER_HALF_SPAN) {
event_clear(chan);
} else {
break;
}
}

cc_val = now + cc_inc;
cc_inc++;
} else {
Expand Down

0 comments on commit 31c11a5

Please sign in to comment.