From 72c2bfa9ec066108fa68781f25f58b5cf308a464 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Tue, 16 Dec 2025 11:04:38 +0100 Subject: [PATCH] [draft] nrfx grtc interval Signed-off-by: Adam Kondraciuk --- drivers/timer/nrf_grtc_timer.c | 72 +++++++++++++++++-- dts/bindings/timer/nordic,nrf-grtc.yaml | 6 ++ include/zephyr/drivers/timer/nrf_grtc_timer.h | 5 ++ .../hal_nordic/nrfx/nrfx_reserved_resources.h | 3 + .../boards/nrf54l15dk_nrf54l15_cpuapp.overlay | 1 + tests/drivers/timer/nrf_grtc_timer/prj.conf | 3 + tests/drivers/timer/nrf_grtc_timer/src/main.c | 67 ++++++++++++++--- 7 files changed, 143 insertions(+), 14 deletions(-) diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c index faecda31b472..9f645f804efc 100644 --- a/drivers/timer/nrf_grtc_timer.c +++ b/drivers/timer/nrf_grtc_timer.c @@ -172,7 +172,24 @@ int32_t z_nrf_grtc_timer_chan_alloc(void) if (ext_channels_allocated >= EXT_CHAN_COUNT) { return -ENOMEM; } - err_code = nrfx_grtc_channel_alloc(&chan); + err_code = nrfx_grtc_channel_alloc(&chan, 0); + if (err_code < 0) { + return -ENOMEM; + } + ext_channels_allocated++; + return (int32_t)chan; +} + +int32_t z_nrf_grtc_timer_special_chan_alloc(void) +{ + uint8_t chan; + int err_code; + + /* Prevent allocating all available channels - one must be left for system purposes. */ + if (ext_channels_allocated >= EXT_CHAN_COUNT) { + return -ENOMEM; + } + err_code = nrfx_grtc_channel_alloc(&chan, NRFX_GRTC_EXTENDED_CHANNEL_FEATURES); if (err_code < 0) { return -ENOMEM; } @@ -262,6 +279,49 @@ static int compare_set(int32_t chan, uint64_t target_time, return ret; } +static void interval_set_nolocks(int32_t chan, uint32_t interval_value, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + nrfx_grtc_channel_t user_channel_data = { + .handler = handler, + .p_context = user_data, + .channel = chan, + }; + + nrfx_grtc_syscounter_cc_interval_set(chan, interval_value); + nrfx_grtc_channel_callback_set(chan, user_channel_data.handler, user_channel_data.p_context); + +} + +static void interval_set(int32_t chan, uint32_t interval_value, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + bool key = compare_int_lock(chan); + interval_set_nolocks(chan, interval_value, handler, user_data); + + compare_int_unlock(chan, key); +} + +int z_nrf_grtc_timer_interval_set(int32_t chan, uint32_t interval_value, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + if (NRFX_BIT((uint32_t)chan) && NRFX_GRTC_CONFIG_EXTENDED_CC_CHANNELS_MASK == 0) + { + return -ENOMEM; + } + if (handler == NULL) { + return -EINVAL; + } + interval_set(chan, interval_value, (nrfx_grtc_cc_handler_t)handler, user_data); + + return 0; +} + +int z_nrf_grtc_timer_interval_stop(int32_t chan) +{ + nrfy_grtc_sys_counter_compare_event_disable(NRF_GRTC, chan); +} + int z_nrf_grtc_timer_set(int32_t chan, uint64_t target_time, z_nrf_grtc_timer_compare_handler_t handler, void *user_data) { @@ -479,16 +539,18 @@ static int sys_clock_driver_init(void) return err_code; } -#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) - err_code = nrfx_grtc_syscounter_start(true, &system_clock_channel_data.channel); + err_code = nrfx_grtc_channel_alloc(&system_clock_channel_data.channel, 0); if (err_code < 0) { return err_code; } -#else - err_code = nrfx_grtc_channel_alloc(&system_clock_channel_data.channel); + +#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) + err_code = nrfx_grtc_syscounter_start(true); if (err_code < 0) { return err_code; } +#else + #endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ last_count = (counter() / CYC_PER_TICK) * CYC_PER_TICK; diff --git a/dts/bindings/timer/nordic,nrf-grtc.yaml b/dts/bindings/timer/nordic,nrf-grtc.yaml index 5b57c8dbeae5..a6b8c19a7992 100644 --- a/dts/bindings/timer/nordic,nrf-grtc.yaml +++ b/dts/bindings/timer/nordic,nrf-grtc.yaml @@ -52,3 +52,9 @@ properties: description: | Clock frequency information for tick increment operations, this default value comes from the nRF54L15 datasheet. + + extended-channels: + type: array + description: | + List of channels in a split-ownership peripheral that are to be owned + for use by the compiled CPU. diff --git a/include/zephyr/drivers/timer/nrf_grtc_timer.h b/include/zephyr/drivers/timer/nrf_grtc_timer.h index 5a51df217442..e8864c8204db 100644 --- a/include/zephyr/drivers/timer/nrf_grtc_timer.h +++ b/include/zephyr/drivers/timer/nrf_grtc_timer.h @@ -36,6 +36,8 @@ typedef void (*z_nrf_grtc_timer_compare_handler_t)(int32_t id, uint64_t expire_t */ int32_t z_nrf_grtc_timer_chan_alloc(void); +int32_t z_nrf_grtc_timer_special_chan_alloc(void); + /** @brief Free GRTC capture/compare channel. * * @param chan Previously allocated channel ID. @@ -125,6 +127,9 @@ int z_nrf_grtc_timer_compare_read(int32_t chan, uint64_t *val); int z_nrf_grtc_timer_set(int32_t chan, uint64_t target_time, z_nrf_grtc_timer_compare_handler_t handler, void *user_data); +int z_nrf_grtc_timer_interval_set(int32_t chan, uint32_t interval_value, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data); + /** @brief Abort a timer requested with z_nrf_grtc_timer_set(). * * If an abort operation is performed too late it is still possible for an event diff --git a/modules/hal_nordic/nrfx/nrfx_reserved_resources.h b/modules/hal_nordic/nrfx/nrfx_reserved_resources.h index 9958699723ff..169dce241d2b 100644 --- a/modules/hal_nordic/nrfx/nrfx_reserved_resources.h +++ b/modules/hal_nordic/nrfx/nrfx_reserved_resources.h @@ -42,6 +42,9 @@ #define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS \ (DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), owned_channels, 0) - \ DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), child_owned_channels, 0)) +#define NRFX_GRTC_CONFIG_EXTENDED_CC_CHANNELS_MASK \ + (NRFX_CONFIG_MASK_DT(DT_INST(0, nordic_nrf_grtc), extended_channels) & \ + ~NRFX_CONFIG_MASK_DT(DT_INST(0, nordic_nrf_grtc), child_owned_channels)) #endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) */ /* diff --git a/tests/drivers/timer/nrf_grtc_timer/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/tests/drivers/timer/nrf_grtc_timer/boards/nrf54l15dk_nrf54l15_cpuapp.overlay index 7bcede529b0e..c6379446dbca 100644 --- a/tests/drivers/timer/nrf_grtc_timer/boards/nrf54l15dk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/timer/nrf_grtc_timer/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -2,6 +2,7 @@ &grtc { interrupts = <228 2>; + extended-channels = <0>; }; test_timer: &timer21 { diff --git a/tests/drivers/timer/nrf_grtc_timer/prj.conf b/tests/drivers/timer/nrf_grtc_timer/prj.conf index 93926f090b7e..1b1f16910e41 100644 --- a/tests/drivers/timer/nrf_grtc_timer/prj.conf +++ b/tests/drivers/timer/nrf_grtc_timer/prj.conf @@ -6,3 +6,6 @@ CONFIG_XOSHIRO_RANDOM_GENERATOR=y CONFIG_LOG_PRINTK=y CONFIG_CPU_LOAD=y CONFIG_CPU_LOAD_USE_COUNTER=y +CONFIG_LOG_MODE_DEFERRED=y +#CONFIG_DEBUG_OPTIMIZATIONS=y +CONFIG_SPEED_OPTIMIZATIONS=y \ No newline at end of file diff --git a/tests/drivers/timer/nrf_grtc_timer/src/main.c b/tests/drivers/timer/nrf_grtc_timer/src/main.c index 2acc99f61b75..3502f2e0533d 100644 --- a/tests/drivers/timer/nrf_grtc_timer/src/main.c +++ b/tests/drivers/timer/nrf_grtc_timer/src/main.c @@ -13,25 +13,34 @@ #include #include #include +#include LOG_MODULE_REGISTER(test, 1); #define GRTC_SLEW_TICKS 10 #define NUMBER_OF_TRIES 2000 +#define NUMBER_OF_INTERVAL_EVENTS 10 #define CYC_PER_TICK \ ((uint64_t)sys_clock_hw_cycles_per_sec() / (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC) #define TIMER_COUNT_TIME_MS 10 +#define INTERVAL_COUNT_TIME_MS 50 #define WAIT_FOR_TIMER_EVENT_TIME_MS TIMER_COUNT_TIME_MS + 5 -static volatile uint8_t compare_isr_call_counter; +BUILD_ASSERT(INTERVAL_COUNT_TIME_MS * 1000 <= UINT16_MAX, "Too large value for test_timer_interval_mode."); + +static volatile uint32_t compare_isr_call_counter; /* GRTC timer compare interrupt handler */ static void timer_compare_interrupt_handler(int32_t id, uint64_t expire_time, void *user_data) { - compare_isr_call_counter++; - TC_PRINT("Compare value reached, user data: '%s'\n", (char *)user_data); - TC_PRINT("Call counter: %d\n", compare_isr_call_counter); + if (id == 0) { + nrf_gpio_pin_set(3); + compare_isr_call_counter++; + nrf_gpio_pin_clear(3); + } + //TC_PRINT("Compare value reached, user data: '%s'\n", (char *)user_data); + //TC_PRINT("Call counter: %d\n", compare_isr_call_counter); } - +#if 0 ZTEST(nrf_grtc_timer, test_get_ticks) { k_timeout_t t = K_MSEC(1); @@ -160,6 +169,46 @@ ZTEST(nrf_grtc_timer, test_timer_abort_in_compare_mode) compare_isr_call_counter); z_nrf_grtc_timer_chan_free(channel); } +#endif +ZTEST(nrf_grtc_timer, test_timer_interval_mode) +{ + int err; + nrf_gpio_cfg_output(3); + nrf_gpio_cfg_output(2); + nrf_gpio_pin_clear(3); + nrf_gpio_pin_set(2); + uint64_t test_ticks = 0; + uint64_t compare_value = 0; + char user_data[] = "test_timer_interval_mode\n"; + int32_t channel = z_nrf_grtc_timer_special_chan_alloc(); + + TC_PRINT("Allocated GRTC channel %d\n", channel); + if (channel < 0) { + TC_PRINT("Failed to allocate GRTC channel, chan=%d\n", channel); + ztest_test_fail(); + } + + compare_isr_call_counter = 0; + test_ticks = INTERVAL_COUNT_TIME_MS * 1000; +nrf_gpio_pin_clear(2); + err = z_nrf_grtc_timer_interval_set(channel, test_ticks, timer_compare_interrupt_handler, + (void *)user_data); +nrf_gpio_pin_set(2); + //zassert_equal(err, 0, "z_nrf_grtc_timer_set raised an error: %d", err); + + k_busy_wait(NUMBER_OF_INTERVAL_EVENTS * test_ticks); +nrf_gpio_pin_clear(2); + //k_busy_wait(1); + + z_nrf_grtc_timer_abort(channel); + TC_PRINT("Interval events count: %d\n", compare_isr_call_counter); + TC_PRINT("Compare event register address: %X\n", + z_nrf_grtc_timer_compare_evt_address_get(channel)); + + zassert_equal(compare_isr_call_counter, NUMBER_OF_INTERVAL_EVENTS, "Compare isr call counter: %d", + compare_isr_call_counter); + z_nrf_grtc_timer_chan_free(channel); +} enum test_timer_state { TIMER_IDLE, @@ -406,9 +455,9 @@ static void grtc_stress_test(bool busy_sim_en) #endif } -ZTEST(nrf_grtc_timer, test_stress) -{ - grtc_stress_test(false); -} +//ZTEST(nrf_grtc_timer, test_stress) +//{ +// grtc_stress_test(false); +//} ZTEST_SUITE(nrf_grtc_timer, NULL, NULL, NULL, NULL, NULL);