Skip to content

Commit 7967848

Browse files
ankunsgmarull
authored andcommitted
[nrf fromtree] drivers: timer: add z_nrf_rtc_timer_exact_set
The function `z_nrf_rtc_timer_exact_set` is added to allow setting compare channel without possible creeping of cc val. Signed-off-by: Andrzej Kuros <[email protected]> (cherry picked from commit a6615ac)
1 parent b10f4b8 commit 7967848

File tree

2 files changed

+77
-13
lines changed

2 files changed

+77
-13
lines changed

drivers/timer/nrf_rtc_timer.c

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,20 @@ uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t)
236236
* @param[in] chan A channel for which a new CC value is to be set.
237237
*
238238
* @param[in] req_cc Requested CC register value to be set.
239+
*
240+
* @param[in] exact Use @c false to allow CC adjustment if @c req_cc value is
241+
* close to the current value of the timer.
242+
* Use @c true to disallow CC adjustment. The function can
243+
* fail with -EINVAL result if @p req_cc is too close to the
244+
* current value.
245+
*
246+
* @retval 0 The requested CC has been set successfully.
247+
* @retval -EINVAL The requested CC value could not be reliably set.
239248
*/
240-
static void set_alarm(int32_t chan, uint32_t req_cc)
249+
static int set_alarm(int32_t chan, uint32_t req_cc, bool exact)
241250
{
251+
int ret = 0;
252+
242253
/* Ensure that the value exposed in this driver API is consistent with
243254
* assumptions of this function.
244255
*/
@@ -305,9 +316,16 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
305316
now = counter();
306317
if (counter_sub(now, req_cc) > COUNTER_HALF_SPAN) {
307318
event_clear(chan);
319+
if (exact) {
320+
ret = -EINVAL;
321+
break;
322+
}
308323
} else {
309324
break;
310325
}
326+
} else if (exact) {
327+
ret = -EINVAL;
328+
break;
311329
}
312330

313331
cc_val = now + cc_inc;
@@ -316,11 +334,13 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
316334
break;
317335
}
318336
}
337+
338+
return ret;
319339
}
320340

321341
static int compare_set_nolocks(int32_t chan, uint64_t target_time,
322342
z_nrf_rtc_timer_compare_handler_t handler,
323-
void *user_data)
343+
void *user_data, bool exact)
324344
{
325345
int ret = 0;
326346
uint32_t cc_value = absolute_time_to_cc(target_time);
@@ -336,29 +356,33 @@ static int compare_set_nolocks(int32_t chan, uint64_t target_time,
336356
/* Target time is valid and is different than currently set.
337357
* Set CC value.
338358
*/
339-
set_alarm(chan, cc_value);
359+
ret = set_alarm(chan, cc_value, exact);
340360
}
341-
} else {
361+
} else if (!exact) {
342362
/* Force ISR handling when exiting from critical section. */
343363
atomic_or(&force_isr_mask, BIT(chan));
364+
} else {
365+
ret = -EINVAL;
344366
}
345367

346-
cc_data[chan].target_time = target_time;
347-
cc_data[chan].callback = handler;
348-
cc_data[chan].user_context = user_data;
368+
if (ret == 0) {
369+
cc_data[chan].target_time = target_time;
370+
cc_data[chan].callback = handler;
371+
cc_data[chan].user_context = user_data;
372+
}
349373

350374
return ret;
351375
}
352376

353377
static int compare_set(int32_t chan, uint64_t target_time,
354378
z_nrf_rtc_timer_compare_handler_t handler,
355-
void *user_data)
379+
void *user_data, bool exact)
356380
{
357381
bool key;
358382

359383
key = compare_int_lock(chan);
360384

361-
int ret = compare_set_nolocks(chan, target_time, handler, user_data);
385+
int ret = compare_set_nolocks(chan, target_time, handler, user_data, exact);
362386

363387
compare_int_unlock(chan, key);
364388

@@ -371,7 +395,16 @@ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
371395
{
372396
__ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT);
373397

374-
return compare_set(chan, target_time, handler, user_data);
398+
return compare_set(chan, target_time, handler, user_data, false);
399+
}
400+
401+
int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time,
402+
z_nrf_rtc_timer_compare_handler_t handler,
403+
void *user_data)
404+
{
405+
__ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT);
406+
407+
return compare_set(chan, target_time, handler, user_data, true);
375408
}
376409

377410
void z_nrf_rtc_timer_abort(int32_t chan)
@@ -452,7 +485,7 @@ static void sys_clock_timeout_handler(int32_t chan,
452485
* so it won't get preempted by the interrupt.
453486
*/
454487
compare_set(chan, last_count + CYC_PER_TICK,
455-
sys_clock_timeout_handler, NULL);
488+
sys_clock_timeout_handler, NULL, false);
456489
}
457490

458491
sys_clock_announce(dticks);
@@ -652,7 +685,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
652685

653686
uint64_t target_time = cyc + last_count;
654687

655-
compare_set(0, target_time, sys_clock_timeout_handler, NULL);
688+
compare_set(0, target_time, sys_clock_timeout_handler, NULL, false);
656689
}
657690

658691
uint32_t sys_clock_elapsed(void)
@@ -730,7 +763,7 @@ static int sys_clock_driver_init(void)
730763
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
731764
MAX_CYCLES : CYC_PER_TICK;
732765

733-
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL);
766+
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false);
734767

735768
z_nrf_clock_control_lf_on(mode);
736769

include/zephyr/drivers/timer/nrf_rtc_timer.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,42 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan);
127127
* @retval 0 if the compare channel was set successfully.
128128
* @retval -EINVAL if provided target time was further than
129129
* @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future.
130+
*
131+
* @sa @ref z_nrf_rtc_timer_exact_set
130132
*/
131133
int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
132134
z_nrf_rtc_timer_compare_handler_t handler,
133135
void *user_data);
134136

137+
/** @brief Try to set compare channel exactly to given value.
138+
*
139+
* @note This function is similar to @ref z_nrf_rtc_timer_set, but the compare
140+
* channel will be set to expected value only when it can be guaranteed that
141+
* the hardware event will be generated exactly at expected @c target_time in
142+
* the future. If the @c target_time is in the past or so close in the future
143+
* that the reliable generation of event would require adjustment of compare
144+
* value (as would @ref z_nrf_rtc_timer_set function do), neither the hardware
145+
* event nor interrupt will be generated and the function fails.
146+
*
147+
* @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT.
148+
*
149+
* @param target_time Absolute target time in ticks.
150+
*
151+
* @param handler User function called in the context of the RTC interrupt.
152+
*
153+
* @param user_data Data passed to the handler.
154+
*
155+
* @retval 0 if the compare channel was set successfully.
156+
* @retval -EINVAL if provided target time was further than
157+
* @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future
158+
* or the target time is in the past or is so close in the future that
159+
* event generation could not be guaranteed without adjusting
160+
* compare value of that channel.
161+
*/
162+
int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time,
163+
z_nrf_rtc_timer_compare_handler_t handler,
164+
void *user_data);
165+
135166
/** @brief Abort a timer requested with @ref z_nrf_rtc_timer_set.
136167
*
137168
* If an abort operation is performed too late it is still possible for an event

0 commit comments

Comments
 (0)