tests: drivers: nrf_rtc_timer: Add a test case to check rescheduling
Add a test case that schedules an alarm and then, after a delay that is changed in every iteration, tries to reschedule it to one cycle later. This reveals a problem in the current nrf_rtc_timer implementation that in certain conditions a scheduled timeout may be missed and its expiration is handled 512 seconds later (when the system timer overflows). Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
This commit is contained in:
parent
5786b63e6c
commit
8e8644ba6a
1 changed files with 63 additions and 0 deletions
|
@ -477,6 +477,69 @@ ZTEST(nrf_rtc_timer, test_next_cycle_timeouts)
|
|||
z_nrf_rtc_timer_chan_free(chan);
|
||||
}
|
||||
|
||||
static void tight_rescheduling_handler(int32_t chan,
|
||||
uint64_t expire_time,
|
||||
void *user_data)
|
||||
{
|
||||
if (user_data) {
|
||||
*(bool *)user_data = true;
|
||||
}
|
||||
}
|
||||
|
||||
ZTEST(nrf_rtc_timer, test_tight_rescheduling)
|
||||
{
|
||||
int32_t chan;
|
||||
volatile bool expired;
|
||||
/* This test tries to schedule an alarm to CYCLE_DIFF cycles from
|
||||
* the current moment and then, after a delay that is changed in
|
||||
* each iteration, tries to reschedule this alarm to one cycle later.
|
||||
* It does not matter if the first alarm actually occurs, the key
|
||||
* thing is to always get the second one.
|
||||
*/
|
||||
enum {
|
||||
CYCLE_DIFF = 5,
|
||||
/* One RTC cycle is ~30.5 us. Check a range of delays from
|
||||
* more than one cycle before the moment on which the first
|
||||
* alarm is scheduled to a few microseconds after that alarm
|
||||
* (when it is actually too late for rescheduling).
|
||||
*/
|
||||
DELAY_MIN = 30 * CYCLE_DIFF - 40,
|
||||
DELAY_MAX = 30 * CYCLE_DIFF + 10,
|
||||
};
|
||||
|
||||
chan = z_nrf_rtc_timer_chan_alloc();
|
||||
zassert_true(chan > 0, "Failed to allocate RTC channel.");
|
||||
|
||||
/* Repeat the whole test a couple of times to get also (presumably)
|
||||
* various micro delays resulting from execution of the test routine
|
||||
* itself asynchronously to the RTC.
|
||||
*/
|
||||
for (uint32_t i = 0; i < 20; ++i) {
|
||||
for (uint32_t delay = DELAY_MIN; delay <= DELAY_MAX; ++delay) {
|
||||
uint64_t start = z_nrf_rtc_timer_read();
|
||||
|
||||
z_nrf_rtc_timer_set(chan, start + CYCLE_DIFF,
|
||||
tight_rescheduling_handler, NULL);
|
||||
|
||||
k_busy_wait(delay);
|
||||
|
||||
expired = false;
|
||||
z_nrf_rtc_timer_set(chan, start + CYCLE_DIFF + 1,
|
||||
tight_rescheduling_handler, (void *)&expired);
|
||||
|
||||
while (!expired &&
|
||||
(z_nrf_rtc_timer_read() - start) <
|
||||
CYCLE_DIFF + 10) {
|
||||
}
|
||||
zassert_true(expired,
|
||||
"Timeout expiration missed (d: %u us, i: %u)",
|
||||
delay, i);
|
||||
}
|
||||
}
|
||||
|
||||
z_nrf_rtc_timer_chan_free(chan);
|
||||
}
|
||||
|
||||
static void *rtc_timer_setup(void)
|
||||
{
|
||||
init_zli_timer0();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue