From 6ea3a2e533ed17cb561377a74972c55790a19990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Stasiak?= Date: Mon, 23 Jun 2025 12:53:29 +0200 Subject: [PATCH 1/2] [nrf fromlist] drivers: timer: nrf_rtc_timer: Allow use of custom bit width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allowed use of counter bit width lower than hardware 24. In that case, PPI connection is established to trigger clear task once maximum value is reached. Upstream PR #: 92025 Signed-off-by: Michał Stasiak --- drivers/timer/Kconfig.nrf_rtc | 7 ++ drivers/timer/nrf_rtc_timer.c | 77 ++++++++++++++++++-- include/zephyr/drivers/timer/nrf_rtc_timer.h | 2 +- tests/drivers/timer/nrf_rtc_timer/src/main.c | 11 ++- 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/drivers/timer/Kconfig.nrf_rtc b/drivers/timer/Kconfig.nrf_rtc index 729dc8d362a..82228d453ca 100644 --- a/drivers/timer/Kconfig.nrf_rtc +++ b/drivers/timer/Kconfig.nrf_rtc @@ -9,6 +9,7 @@ config NRF_RTC_TIMER depends on SOC_COMPATIBLE_NRF select TICKLESS_CAPABLE select SYSTEM_TIMER_HAS_DISABLE_SUPPORT + select NRFX_PPI if SOC_NRF52832 depends on !$(dt_nodelabel_enabled,rtc1) help This module implements a kernel device driver for the nRF Real Time @@ -42,4 +43,10 @@ config NRF_RTC_TIMER_TRIGGER_OVERFLOW When enabled, a function can be used to trigger RTC overflow and effectively shift time into the future. +config NRF_RTC_COUNTER_BIT_WIDTH + int + default 15 if SOC_NRF52832 + default 24 + range 15 24 + endif # NRF_RTC_TIMER diff --git a/drivers/timer/nrf_rtc_timer.c b/drivers/timer/nrf_rtc_timer.c index 0fdf951f925..a70cc19b7e9 100644 --- a/drivers/timer/nrf_rtc_timer.c +++ b/drivers/timer/nrf_rtc_timer.c @@ -17,23 +17,34 @@ #include #include +#define RTC_BIT_WIDTH 24 + +#if (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < RTC_BIT_WIDTH) +#define CUSTOM_COUNTER_BIT_WIDTH 1 +#define WRAP_CH 1 +#include "nrfx_ppi.h" +#else +#define CUSTOM_COUNTER_BIT_WIDTH 0 +#endif + #define RTC_PRETICK (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && \ IS_ENABLED(CONFIG_SOC_NRF5340_CPUNET)) #define EXT_CHAN_COUNT CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT -#define CHAN_COUNT (EXT_CHAN_COUNT + 1) +#define CHAN_COUNT (EXT_CHAN_COUNT + 1 + CUSTOM_COUNTER_BIT_WIDTH) #define RTC NRF_RTC1 #define RTC_IRQn NRFX_IRQ_NUMBER_GET(RTC) #define RTC_LABEL rtc1 #define CHAN_COUNT_MAX (RTC1_CC_NUM - (RTC_PRETICK ? 1 : 0)) +#define SYS_CLOCK_CH 0 BUILD_ASSERT(CHAN_COUNT <= CHAN_COUNT_MAX, "Not enough compare channels"); /* Ensure that counter driver for RTC1 is not enabled. */ BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(RTC_LABEL), disabled), "Counter for RTC1 must be disabled"); -#define COUNTER_BIT_WIDTH 24U +#define COUNTER_BIT_WIDTH CONFIG_NRF_RTC_COUNTER_BIT_WIDTH #define COUNTER_SPAN BIT(COUNTER_BIT_WIDTH) #define COUNTER_MAX (COUNTER_SPAN - 1U) #define COUNTER_HALF_SPAN (COUNTER_SPAN / 2U) @@ -139,7 +150,7 @@ uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan) { #if defined(RTC_TASKS_CAPTURE_TASKS_CAPTURE_Msk) __ASSERT_NO_MSG(chan >= 0 && chan < CHAN_COUNT); - if (chan == 0) { + if (chan == SYS_CLOCK_CH) { return 0; } @@ -264,6 +275,15 @@ static int set_alarm(int32_t chan, uint32_t req_cc, bool exact) */ enum { MIN_CYCLES_FROM_NOW = 3 }; uint32_t cc_val = req_cc; + +#if CUSTOM_COUNTER_BIT_WIDTH + /* If a CC value is 0 when a CLEAR task is set, this will not + * trigger a COMAPRE event. Need to use 1 instead. + */ + if (cc_val % COUNTER_MAX == 0) { + cc_val = 1; + } +#endif uint32_t cc_inc = MIN_CYCLES_FROM_NOW; /* Disable event routing for the channel to avoid getting a COMPARE @@ -427,6 +447,17 @@ uint64_t z_nrf_rtc_timer_read(void) uint32_t cntr = counter(); +#if CUSTOM_COUNTER_BIT_WIDTH + /* If counter is equal to it maximum value while val is greater + * than anchor, then we can assume that overflow has been recorded + * in the overflow_cnt, but clear task has not been triggered yet. + * Treat counter as if it has been cleared. + */ + if ((cntr == COUNTER_MAX) && (val > anchor)) { + cntr = 0; + } +#endif + val += cntr; if (cntr < OVERFLOW_RISK_RANGE_END) { @@ -565,8 +596,13 @@ void rtc_nrf_isr(const void *arg) rtc_pretick_rtc1_isr_hook(); } +#if CUSTOM_COUNTER_BIT_WIDTH + if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_COMPARE1_MASK) && + nrfy_rtc_events_process(RTC, NRF_RTC_INT_COMPARE1_MASK)) { +#else if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) && nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) { +#endif overflow_cnt++; } @@ -625,7 +661,7 @@ int z_nrf_rtc_timer_trigger_overflow(void) uint64_t now = z_nrf_rtc_timer_read(); if (err == 0) { - sys_clock_timeout_handler(0, now, NULL); + sys_clock_timeout_handler(SYS_CLOCK_CH, now, NULL); } bail: full_int_unlock(mcu_critical_state); @@ -682,7 +718,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, false); + compare_set(SYS_CLOCK_CH, target_time, sys_clock_timeout_handler, NULL, false); } uint32_t sys_clock_elapsed(void) @@ -702,7 +738,9 @@ uint32_t sys_clock_cycle_get_32(void) static void int_event_disable_rtc(void) { uint32_t mask = NRF_RTC_INT_TICK_MASK | +#if !CUSTOM_COUNTER_BIT_WIDTH NRF_RTC_INT_OVERFLOW_MASK | +#endif NRF_RTC_INT_COMPARE0_MASK | NRF_RTC_INT_COMPARE1_MASK | NRF_RTC_INT_COMPARE2_MASK | @@ -734,7 +772,9 @@ static int sys_clock_driver_init(void) nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } +#if !CUSTOM_COUNTER_BIT_WIDTH nrfy_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK); +#endif NVIC_ClearPendingIRQ(RTC_IRQn); @@ -747,13 +787,13 @@ static int sys_clock_driver_init(void) int_mask = BIT_MASK(CHAN_COUNT); if (CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT) { - alloc_mask = BIT_MASK(EXT_CHAN_COUNT) << 1; + alloc_mask = BIT_MASK(CHAN_COUNT) & ~BIT(SYS_CLOCK_CH); } uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? MAX_CYCLES : CYC_PER_TICK; - compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false); + compare_set(SYS_CLOCK_CH, initial_timeout, sys_clock_timeout_handler, NULL, false); #if defined(CONFIG_CLOCK_CONTROL_NRF) static const enum nrf_lfclk_start_mode mode = @@ -766,6 +806,29 @@ static int sys_clock_driver_init(void) z_nrf_clock_control_lf_on(mode); #endif +#if CUSTOM_COUNTER_BIT_WIDTH + /* WRAP_CH reserved for wrapping. */ + alloc_mask &= ~BIT(WRAP_CH); + + nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(WRAP_CH); + nrfx_err_t result; + nrf_ppi_channel_t ch; + + nrfy_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(WRAP_CH)); + nrfy_rtc_cc_set(RTC, WRAP_CH, COUNTER_MAX); + uint32_t evt_addr; + uint32_t task_addr; + + evt_addr = nrfy_rtc_event_address_get(RTC, evt); + task_addr = nrfy_rtc_task_address_get(RTC, NRF_RTC_TASK_CLEAR); + + result = nrfx_ppi_channel_alloc(&ch); + if (result != NRFX_SUCCESS) { + return -ENODEV; + } + (void)nrfx_ppi_channel_assign(ch, evt_addr, task_addr); + (void)nrfx_ppi_channel_enable(ch); +#endif return 0; } diff --git a/include/zephyr/drivers/timer/nrf_rtc_timer.h b/include/zephyr/drivers/timer/nrf_rtc_timer.h index 57340098c23..de1ad940cf5 100644 --- a/include/zephyr/drivers/timer/nrf_rtc_timer.h +++ b/include/zephyr/drivers/timer/nrf_rtc_timer.h @@ -15,7 +15,7 @@ extern "C" { /** @brief Maximum allowed time span that is considered to be in the future. */ -#define NRF_RTC_TIMER_MAX_SCHEDULE_SPAN BIT(23) +#define NRF_RTC_TIMER_MAX_SCHEDULE_SPAN BIT(CONFIG_NRF_RTC_COUNTER_BIT_WIDTH - 1) /** @brief RTC timer compare event handler. * diff --git a/tests/drivers/timer/nrf_rtc_timer/src/main.c b/tests/drivers/timer/nrf_rtc_timer/src/main.c index ebdb1c18a3f..00393c8587d 100644 --- a/tests/drivers/timer/nrf_rtc_timer/src/main.c +++ b/tests/drivers/timer/nrf_rtc_timer/src/main.c @@ -321,7 +321,11 @@ ZTEST(nrf_rtc_timer, test_resetting_cc) struct test_data test_data = { .target_time = now + 5, .window = 0, - .delay = 0, + /* For lower bit width, target_time may be equal to maximum counter value. + * In such case, due to PPI connection clearing the timer, counter value + * read in the handler may be slightly off the set counter value. + */ + .delay = (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < 24) ? 2 : 0, .err = -EINVAL }; @@ -361,6 +365,11 @@ static void overflow_sched_handler(int32_t id, uint64_t expire_time, */ ZTEST(nrf_rtc_timer, test_overflow) { + /* For bit width lower than default 24, overflow injection is not possible. */ + if (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < 24) { + ztest_test_skip(); + } + PRINT("RTC ticks before overflow injection: %u\r\n", (uint32_t)z_nrf_rtc_timer_read()); From bbfc7cb2d22921e5d88ad017bd8e6aed04c34551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Stasiak?= Date: Wed, 16 Jul 2025 14:16:24 +0200 Subject: [PATCH 2/2] [nrf fromlist] tests: drivers: counter_nrf_rtc: test fixed top on nRF52832 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added overlay for the board. Upstream PR #: 92025 Signed-off-by: Michał Stasiak --- .../fixed_top/boards/nrf52dk_nrf52832.overlay | 8 ++++++++ .../counter/counter_nrf_rtc/fixed_top/testcase.yaml | 1 + 2 files changed, 9 insertions(+) create mode 100644 tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52dk_nrf52832.overlay diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52dk_nrf52832.overlay b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52dk_nrf52832.overlay new file mode 100644 index 00000000000..ebfed9cf903 --- /dev/null +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/boards/nrf52dk_nrf52832.overlay @@ -0,0 +1,8 @@ +&rtc0 { + status = "okay"; + fixed-top; +}; +&rtc2 { + status = "okay"; + fixed-top; +}; diff --git a/tests/drivers/counter/counter_nrf_rtc/fixed_top/testcase.yaml b/tests/drivers/counter/counter_nrf_rtc/fixed_top/testcase.yaml index 38dda6dc88c..763c6896d07 100644 --- a/tests/drivers/counter/counter_nrf_rtc/fixed_top/testcase.yaml +++ b/tests/drivers/counter/counter_nrf_rtc/fixed_top/testcase.yaml @@ -5,6 +5,7 @@ tests: - counter depends_on: counter platform_allow: + - nrf52dk/nrf52832 - nrf52840dk/nrf52840 - nrf52_bsim - nrf54h20dk/nrf54h20/cpuapp