49
49
#define COUNTER_SPAN (GRTC_SYSCOUNTERL_VALUE_Msk | ((uint64_t)GRTC_SYSCOUNTERH_VALUE_Msk << 32))
50
50
#define MAX_ABS_TICKS (COUNTER_SPAN / CYC_PER_TICK)
51
51
52
- #define MAX_TICKS \
53
- (((COUNTER_SPAN / CYC_PER_TICK) > INT_MAX) ? INT_MAX : (COUNTER_SPAN / CYC_PER_TICK))
54
-
55
- #define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK)
52
+ /* To allow use of CCADD we need to limit max cycles to 31 bits. */
53
+ #define MAX_REL_CYCLES BIT_MASK(31)
54
+ #define MAX_REL_TICKS (MAX_REL_CYCLES / CYC_PER_TICK)
56
55
57
56
#define LFCLK_FREQUENCY_HZ DT_PROP(LFCLK_NODE, clock_frequency)
58
57
58
+ /* Threshold used to determine if there is a risk of unexpected GRTC COMPARE event coming
59
+ * from previous CC value.
60
+ */
61
+ #define LATENCY_THR_TICKS 200
62
+
59
63
#if defined(CONFIG_TEST )
60
64
const int32_t z_sys_timer_irq_for_test = DT_IRQN (GRTC_NODE );
61
65
#endif
62
66
63
67
static void sys_clock_timeout_handler (int32_t id , uint64_t cc_val , void * p_context );
64
68
65
- static struct k_spinlock lock ;
66
69
static uint64_t last_count ; /* Time (SYSCOUNTER value) @last sys_clock_announce() */
70
+ static uint32_t last_elapsed ;
71
+ static uint64_t cc_value ; /* Value that is expected to be in CC register. */
72
+ static uint64_t expired_cc ; /* Value that is expected to be in CC register. */
67
73
static atomic_t int_mask ;
68
74
static uint8_t ext_channels_allocated ;
69
75
static uint64_t grtc_start_value ;
@@ -146,17 +152,13 @@ static void compare_int_unlock(int32_t chan, bool key)
146
152
static void sys_clock_timeout_handler (int32_t id , uint64_t cc_val , void * p_context )
147
153
{
148
154
ARG_UNUSED (id );
155
+ ARG_UNUSED (cc_val );
149
156
ARG_UNUSED (p_context );
150
- uint64_t dticks ;
151
- uint64_t now = counter ();
152
-
153
- if (unlikely (now < cc_val )) {
154
- return ;
155
- }
157
+ uint32_t dticks ;
156
158
157
159
dticks = counter_sub (cc_val , last_count ) / CYC_PER_TICK ;
158
-
159
- last_count += dticks * CYC_PER_TICK ;
160
+ last_count += ( dticks * CYC_PER_TICK );
161
+ expired_cc = cc_val ;
160
162
161
163
if (!IS_ENABLED (CONFIG_TICKLESS_KERNEL )) {
162
164
/* protection is not needed because we are in the GRTC interrupt
@@ -165,6 +167,7 @@ static void sys_clock_timeout_handler(int32_t id, uint64_t cc_val, void *p_conte
165
167
system_timeout_set_abs (last_count + CYC_PER_TICK );
166
168
}
167
169
170
+ last_elapsed = 0 ;
168
171
sys_clock_announce ((int32_t )dticks );
169
172
}
170
173
@@ -368,6 +371,7 @@ uint64_t z_nrf_grtc_timer_startup_value_get(void)
368
371
int z_nrf_grtc_wakeup_prepare (uint64_t wake_time_us )
369
372
{
370
373
nrfx_err_t err_code ;
374
+ static struct k_spinlock lock ;
371
375
static uint8_t systemoff_channel ;
372
376
uint64_t now = counter ();
373
377
nrfx_grtc_sleep_config_t sleep_cfg ;
@@ -428,22 +432,15 @@ int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us)
428
432
}
429
433
#endif /* CONFIG_POWEROFF */
430
434
435
+
431
436
uint32_t sys_clock_cycle_get_32 (void )
432
437
{
433
- k_spinlock_key_t key = k_spin_lock (& lock );
434
- uint32_t ret = (uint32_t )counter ();
435
-
436
- k_spin_unlock (& lock , key );
437
- return ret ;
438
+ return nrf_grtc_sys_counter_low_get (NRF_GRTC );
438
439
}
439
440
440
441
uint64_t sys_clock_cycle_get_64 (void )
441
442
{
442
- k_spinlock_key_t key = k_spin_lock (& lock );
443
- uint64_t ret = counter ();
444
-
445
- k_spin_unlock (& lock , key );
446
- return ret ;
443
+ return counter ();
447
444
}
448
445
449
446
uint32_t sys_clock_elapsed (void )
@@ -452,7 +449,9 @@ uint32_t sys_clock_elapsed(void)
452
449
return 0 ;
453
450
}
454
451
455
- return (uint32_t )(counter_sub (counter (), last_count ) / CYC_PER_TICK );
452
+ last_elapsed = (uint32_t )counter_sub (counter (), last_count );
453
+
454
+ return last_elapsed / CYC_PER_TICK ;
456
455
}
457
456
458
457
static int sys_clock_driver_init (void )
@@ -493,6 +492,10 @@ static int sys_clock_driver_init(void)
493
492
494
493
last_count = (counter () / CYC_PER_TICK ) * CYC_PER_TICK ;
495
494
grtc_start_value = last_count ;
495
+ expired_cc = UINT64_MAX ;
496
+ nrfx_grtc_channel_callback_set (system_clock_channel_data .channel ,
497
+ sys_clock_timeout_handler , NULL );
498
+
496
499
int_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK ;
497
500
if (!IS_ENABLED (CONFIG_TICKLESS_KERNEL )) {
498
501
system_timeout_set_relative (CYC_PER_TICK );
@@ -547,22 +550,47 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
547
550
{
548
551
ARG_UNUSED (idle );
549
552
553
+ if (ticks == 0 ) {
554
+ return ;
555
+ }
556
+
550
557
if (!IS_ENABLED (CONFIG_TICKLESS_KERNEL )) {
551
558
return ;
552
559
}
553
560
554
- ticks = ( ticks == K_TICKS_FOREVER ) ? MAX_TICKS : MIN ( MAX_TICKS , MAX ( ticks , 0 )) ;
561
+ uint32_t ch = system_clock_channel_data . channel ;
555
562
556
- uint64_t delta_time = ticks * CYC_PER_TICK ;
563
+ if ((cc_value == expired_cc ) && (ticks < MAX_REL_TICKS )) {
564
+ uint32_t cyc = ticks * CYC_PER_TICK ;
557
565
558
- uint64_t target_time = counter () + delta_time ;
566
+ /* If it's the first timeout setting after previous expiration and timeout
567
+ * is short so fast method can be used which utilizes relative CC configuration.
568
+ */
569
+ cc_value += cyc ;
570
+ nrfx_grtc_syscounter_cc_rel_set (ch , cyc , NRFX_GRTC_CC_RELATIVE_COMPARE );
571
+ return ;
572
+ }
573
+
574
+ uint64_t cyc = (uint64_t )ticks * CYC_PER_TICK ;
575
+ bool safe_setting = false;
576
+ int64_t prev_cc_val = cc_value ;
559
577
560
- /* Rounded down target_time to the tick boundary
561
- * (but not less than one tick after the last)
578
+ cc_value = last_count + last_elapsed + cyc ;
579
+
580
+ /* In case of timeout abort it may happen that CC is being set to a value
581
+ * that later than previous CC. If previous CC value is not far in the
582
+ * future, there is a risk that COMPARE event will be triggered for that
583
+ * previous CC value. If there is such risk safe procedure must be applied
584
+ * which is more time consuming but ensures that there will be no spurious
585
+ * event.
562
586
*/
563
- target_time = MAX ((target_time - last_count )/CYC_PER_TICK , 1 )* CYC_PER_TICK + last_count ;
587
+ if (prev_cc_val < cc_value ) {
588
+ int64_t now = last_count + last_elapsed ;
589
+
590
+ safe_setting = (prev_cc_val - now ) < LATENCY_THR_TICKS ;
591
+ }
564
592
565
- system_timeout_set_abs ( target_time );
593
+ nrfx_grtc_syscounter_cc_abs_set ( ch , cc_value , safe_setting );
566
594
}
567
595
568
596
#if defined(CONFIG_NRF_GRTC_TIMER_APP_DEFINED_INIT )
0 commit comments