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 Kuroś <andrzej.kuros@nordicsemi.no>
This commit is contained in:
parent
53843c6464
commit
a6615ac11f
2 changed files with 77 additions and 13 deletions
|
@ -232,9 +232,20 @@ uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t)
|
|||
* @param[in] chan A channel for which a new CC value is to be set.
|
||||
*
|
||||
* @param[in] req_cc Requested CC register value to be set.
|
||||
*
|
||||
* @param[in] exact Use @c false to allow CC adjustment if @c req_cc value is
|
||||
* close to the current value of the timer.
|
||||
* Use @c true to disallow CC adjustment. The function can
|
||||
* fail with -EINVAL result if @p req_cc is too close to the
|
||||
* current value.
|
||||
*
|
||||
* @retval 0 The requested CC has been set successfully.
|
||||
* @retval -EINVAL The requested CC value could not be reliably set.
|
||||
*/
|
||||
static void set_alarm(int32_t chan, uint32_t req_cc)
|
||||
static int set_alarm(int32_t chan, uint32_t req_cc, bool exact)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Ensure that the value exposed in this driver API is consistent with
|
||||
* assumptions of this function.
|
||||
*/
|
||||
|
@ -301,9 +312,16 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
|
|||
now = counter();
|
||||
if (counter_sub(now, req_cc) > COUNTER_HALF_SPAN) {
|
||||
event_clear(chan);
|
||||
if (exact) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (exact) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
cc_val = now + cc_inc;
|
||||
|
@ -312,11 +330,13 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compare_set_nolocks(int32_t chan, uint64_t target_time,
|
||||
z_nrf_rtc_timer_compare_handler_t handler,
|
||||
void *user_data)
|
||||
void *user_data, bool exact)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t cc_value = absolute_time_to_cc(target_time);
|
||||
|
@ -332,29 +352,33 @@ static int compare_set_nolocks(int32_t chan, uint64_t target_time,
|
|||
/* Target time is valid and is different than currently set.
|
||||
* Set CC value.
|
||||
*/
|
||||
set_alarm(chan, cc_value);
|
||||
ret = set_alarm(chan, cc_value, exact);
|
||||
}
|
||||
} else {
|
||||
} else if (!exact) {
|
||||
/* Force ISR handling when exiting from critical section. */
|
||||
atomic_or(&force_isr_mask, BIT(chan));
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
cc_data[chan].target_time = target_time;
|
||||
cc_data[chan].callback = handler;
|
||||
cc_data[chan].user_context = user_data;
|
||||
if (ret == 0) {
|
||||
cc_data[chan].target_time = target_time;
|
||||
cc_data[chan].callback = handler;
|
||||
cc_data[chan].user_context = user_data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compare_set(int32_t chan, uint64_t target_time,
|
||||
z_nrf_rtc_timer_compare_handler_t handler,
|
||||
void *user_data)
|
||||
void *user_data, bool exact)
|
||||
{
|
||||
bool key;
|
||||
|
||||
key = compare_int_lock(chan);
|
||||
|
||||
int ret = compare_set_nolocks(chan, target_time, handler, user_data);
|
||||
int ret = compare_set_nolocks(chan, target_time, handler, user_data, exact);
|
||||
|
||||
compare_int_unlock(chan, key);
|
||||
|
||||
|
@ -367,7 +391,16 @@ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
|
|||
{
|
||||
__ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT);
|
||||
|
||||
return compare_set(chan, target_time, handler, user_data);
|
||||
return compare_set(chan, target_time, handler, user_data, false);
|
||||
}
|
||||
|
||||
int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time,
|
||||
z_nrf_rtc_timer_compare_handler_t handler,
|
||||
void *user_data)
|
||||
{
|
||||
__ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT);
|
||||
|
||||
return compare_set(chan, target_time, handler, user_data, true);
|
||||
}
|
||||
|
||||
void z_nrf_rtc_timer_abort(int32_t chan)
|
||||
|
@ -448,7 +481,7 @@ static void sys_clock_timeout_handler(int32_t chan,
|
|||
* so it won't get preempted by the interrupt.
|
||||
*/
|
||||
compare_set(chan, last_count + CYC_PER_TICK,
|
||||
sys_clock_timeout_handler, NULL);
|
||||
sys_clock_timeout_handler, NULL, false);
|
||||
}
|
||||
|
||||
sys_clock_announce(dticks);
|
||||
|
@ -644,7 +677,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
|
|||
|
||||
uint64_t target_time = cyc + last_count;
|
||||
|
||||
compare_set(0, target_time, sys_clock_timeout_handler, NULL);
|
||||
compare_set(0, target_time, sys_clock_timeout_handler, NULL, false);
|
||||
}
|
||||
|
||||
uint32_t sys_clock_elapsed(void)
|
||||
|
@ -722,7 +755,7 @@ static int sys_clock_driver_init(void)
|
|||
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
|
||||
MAX_CYCLES : CYC_PER_TICK;
|
||||
|
||||
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL);
|
||||
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false);
|
||||
|
||||
z_nrf_clock_control_lf_on(mode);
|
||||
|
||||
|
|
|
@ -127,11 +127,42 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan);
|
|||
* @retval 0 if the compare channel was set successfully.
|
||||
* @retval -EINVAL if provided target time was further than
|
||||
* @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future.
|
||||
*
|
||||
* @sa @ref z_nrf_rtc_timer_exact_set
|
||||
*/
|
||||
int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
|
||||
z_nrf_rtc_timer_compare_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
/** @brief Try to set compare channel exactly to given value.
|
||||
*
|
||||
* @note This function is similar to @ref z_nrf_rtc_timer_set, but the compare
|
||||
* channel will be set to expected value only when it can be guaranteed that
|
||||
* the hardware event will be generated exactly at expected @c target_time in
|
||||
* the future. If the @c target_time is in the past or so close in the future
|
||||
* that the reliable generation of event would require adjustment of compare
|
||||
* value (as would @ref z_nrf_rtc_timer_set function do), neither the hardware
|
||||
* event nor interrupt will be generated and the function fails.
|
||||
*
|
||||
* @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT.
|
||||
*
|
||||
* @param target_time Absolute target time in ticks.
|
||||
*
|
||||
* @param handler User function called in the context of the RTC interrupt.
|
||||
*
|
||||
* @param user_data Data passed to the handler.
|
||||
*
|
||||
* @retval 0 if the compare channel was set successfully.
|
||||
* @retval -EINVAL if provided target time was further than
|
||||
* @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future
|
||||
* or the target time is in the past or is so close in the future that
|
||||
* event generation could not be guaranteed without adjusting
|
||||
* compare value of that channel.
|
||||
*/
|
||||
int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time,
|
||||
z_nrf_rtc_timer_compare_handler_t handler,
|
||||
void *user_data);
|
||||
|
||||
/** @brief Abort a timer requested with @ref z_nrf_rtc_timer_set.
|
||||
*
|
||||
* If an abort operation is performed too late it is still possible for an event
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue