@@ -236,9 +236,20 @@ uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t)
236
236
* @param[in] chan A channel for which a new CC value is to be set.
237
237
*
238
238
* @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.
239
248
*/
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 )
241
250
{
251
+ int ret = 0 ;
252
+
242
253
/* Ensure that the value exposed in this driver API is consistent with
243
254
* assumptions of this function.
244
255
*/
@@ -305,9 +316,16 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
305
316
now = counter ();
306
317
if (counter_sub (now , req_cc ) > COUNTER_HALF_SPAN ) {
307
318
event_clear (chan );
319
+ if (exact ) {
320
+ ret = - EINVAL ;
321
+ break ;
322
+ }
308
323
} else {
309
324
break ;
310
325
}
326
+ } else if (exact ) {
327
+ ret = - EINVAL ;
328
+ break ;
311
329
}
312
330
313
331
cc_val = now + cc_inc ;
@@ -316,11 +334,13 @@ static void set_alarm(int32_t chan, uint32_t req_cc)
316
334
break ;
317
335
}
318
336
}
337
+
338
+ return ret ;
319
339
}
320
340
321
341
static int compare_set_nolocks (int32_t chan , uint64_t target_time ,
322
342
z_nrf_rtc_timer_compare_handler_t handler ,
323
- void * user_data )
343
+ void * user_data , bool exact )
324
344
{
325
345
int ret = 0 ;
326
346
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,
336
356
/* Target time is valid and is different than currently set.
337
357
* Set CC value.
338
358
*/
339
- set_alarm (chan , cc_value );
359
+ ret = set_alarm (chan , cc_value , exact );
340
360
}
341
- } else {
361
+ } else if (! exact ) {
342
362
/* Force ISR handling when exiting from critical section. */
343
363
atomic_or (& force_isr_mask , BIT (chan ));
364
+ } else {
365
+ ret = - EINVAL ;
344
366
}
345
367
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
+ }
349
373
350
374
return ret ;
351
375
}
352
376
353
377
static int compare_set (int32_t chan , uint64_t target_time ,
354
378
z_nrf_rtc_timer_compare_handler_t handler ,
355
- void * user_data )
379
+ void * user_data , bool exact )
356
380
{
357
381
bool key ;
358
382
359
383
key = compare_int_lock (chan );
360
384
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 );
362
386
363
387
compare_int_unlock (chan , key );
364
388
@@ -371,7 +395,16 @@ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time,
371
395
{
372
396
__ASSERT_NO_MSG (chan > 0 && chan < CHAN_COUNT );
373
397
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);
375
408
}
376
409
377
410
void z_nrf_rtc_timer_abort (int32_t chan )
@@ -452,7 +485,7 @@ static void sys_clock_timeout_handler(int32_t chan,
452
485
* so it won't get preempted by the interrupt.
453
486
*/
454
487
compare_set (chan , last_count + CYC_PER_TICK ,
455
- sys_clock_timeout_handler , NULL );
488
+ sys_clock_timeout_handler , NULL , false );
456
489
}
457
490
458
491
sys_clock_announce (dticks );
@@ -652,7 +685,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
652
685
653
686
uint64_t target_time = cyc + last_count ;
654
687
655
- compare_set (0 , target_time , sys_clock_timeout_handler , NULL );
688
+ compare_set (0 , target_time , sys_clock_timeout_handler , NULL , false );
656
689
}
657
690
658
691
uint32_t sys_clock_elapsed (void )
@@ -730,7 +763,7 @@ static int sys_clock_driver_init(void)
730
763
uint32_t initial_timeout = IS_ENABLED (CONFIG_TICKLESS_KERNEL ) ?
731
764
MAX_CYCLES : CYC_PER_TICK ;
732
765
733
- compare_set (0 , initial_timeout , sys_clock_timeout_handler , NULL );
766
+ compare_set (0 , initial_timeout , sys_clock_timeout_handler , NULL , false );
734
767
735
768
z_nrf_clock_control_lf_on (mode );
736
769
0 commit comments