Skip to content

Commit f0d01ed

Browse files
drivers: timer: nrf_rtc_timer: Allow use of custom bit width
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. Signed-off-by: Michał Stasiak <michal.stasiak@nordicsemi.no>
1 parent f52d71c commit f0d01ed

File tree

4 files changed

+78
-7
lines changed

4 files changed

+78
-7
lines changed

drivers/timer/Kconfig.nrf_rtc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ config NRF_RTC_TIMER
99
depends on SOC_COMPATIBLE_NRF
1010
select TICKLESS_CAPABLE
1111
select SYSTEM_TIMER_HAS_DISABLE_SUPPORT
12+
select NRFX_PPI if SOC_NRF52832
1213
depends on !$(dt_nodelabel_enabled,rtc1)
1314
help
1415
This module implements a kernel device driver for the nRF Real Time
@@ -42,4 +43,9 @@ config NRF_RTC_TIMER_TRIGGER_OVERFLOW
4243
When enabled, a function can be used to trigger RTC overflow and
4344
effectively shift time into the future.
4445

46+
config NRF_RTC_COUNTER_BIT_WIDTH
47+
int
48+
default 15 if SOC_NRF52832
49+
default 24
50+
4551
endif # NRF_RTC_TIMER

drivers/timer/nrf_rtc_timer.c

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@
1717
#include <haly/nrfy_rtc.h>
1818
#include <zephyr/irq.h>
1919

20+
/* Ensure that selected counter bit width is within its maximum hardware width. */
21+
BUILD_ASSERT(CONFIG_NRF_RTC_COUNTER_BIT_WIDTH <= 24, "Counter bit width exceeds maximum width.");
22+
23+
#if (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < 24)
24+
#define CUSTOM_COUNTER_BIT_WIDTH 1
25+
#include "nrfx_ppi.h"
26+
#else
27+
#define CUSTOM_COUNTER_BIT_WIDTH 0
28+
#endif
29+
2030
#define RTC_PRETICK (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && \
2131
IS_ENABLED(CONFIG_SOC_NRF5340_CPUNET))
2232

2333
#define EXT_CHAN_COUNT CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT
24-
#define CHAN_COUNT (EXT_CHAN_COUNT + 1)
34+
#define CHAN_COUNT (EXT_CHAN_COUNT + 1 + CUSTOM_COUNTER_BIT_WIDTH)
2535

2636
#define RTC NRF_RTC1
2737
#define RTC_IRQn NRFX_IRQ_NUMBER_GET(RTC)
@@ -33,7 +43,7 @@ BUILD_ASSERT(CHAN_COUNT <= CHAN_COUNT_MAX, "Not enough compare channels");
3343
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(RTC_LABEL), disabled),
3444
"Counter for RTC1 must be disabled");
3545

36-
#define COUNTER_BIT_WIDTH 24U
46+
#define COUNTER_BIT_WIDTH CONFIG_NRF_RTC_COUNTER_BIT_WIDTH
3747
#define COUNTER_SPAN BIT(COUNTER_BIT_WIDTH)
3848
#define COUNTER_MAX (COUNTER_SPAN - 1U)
3949
#define COUNTER_HALF_SPAN (COUNTER_SPAN / 2U)
@@ -259,6 +269,15 @@ static int set_alarm(int32_t chan, uint32_t req_cc, bool exact)
259269
*/
260270
enum { MIN_CYCLES_FROM_NOW = 3 };
261271
uint32_t cc_val = req_cc;
272+
273+
#if CUSTOM_COUNTER_BIT_WIDTH
274+
/* If a CC value is 0 when a CLEAR task is set, this will not
275+
* trigger a COMAPRE event. Need to use 1 instead.
276+
*/
277+
if (cc_val % COUNTER_MAX == 0) {
278+
cc_val = 1;
279+
}
280+
#endif
262281
uint32_t cc_inc = MIN_CYCLES_FROM_NOW;
263282

264283
/* Disable event routing for the channel to avoid getting a COMPARE
@@ -422,6 +441,12 @@ uint64_t z_nrf_rtc_timer_read(void)
422441

423442
uint32_t cntr = counter();
424443

444+
#if CUSTOM_COUNTER_BIT_WIDTH
445+
if ((cntr == COUNTER_MAX) && (val > anchor)) {
446+
cntr = 0;
447+
}
448+
#endif
449+
425450
val += cntr;
426451

427452
if (cntr < OVERFLOW_RISK_RANGE_END) {
@@ -560,8 +585,13 @@ void rtc_nrf_isr(const void *arg)
560585
rtc_pretick_rtc1_isr_hook();
561586
}
562587

563-
if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) &&
564-
nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) {
588+
if ((nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) &&
589+
nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) ||
590+
#if CUSTOM_COUNTER_BIT_WIDTH
591+
(nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_COMPARE1_MASK) &&
592+
nrfy_rtc_events_process(RTC, NRF_RTC_INT_COMPARE1_MASK)) ||
593+
#endif
594+
0) {
565595
overflow_cnt++;
566596
}
567597

@@ -697,7 +727,9 @@ uint32_t sys_clock_cycle_get_32(void)
697727
static void int_event_disable_rtc(void)
698728
{
699729
uint32_t mask = NRF_RTC_INT_TICK_MASK |
730+
#if !CUSTOM_COUNTER_BIT_WIDTH
700731
NRF_RTC_INT_OVERFLOW_MASK |
732+
#endif
701733
NRF_RTC_INT_COMPARE0_MASK |
702734
NRF_RTC_INT_COMPARE1_MASK |
703735
NRF_RTC_INT_COMPARE2_MASK |
@@ -729,7 +761,9 @@ static int sys_clock_driver_init(void)
729761
nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan));
730762
}
731763

764+
#if !CUSTOM_COUNTER_BIT_WIDTH
732765
nrfy_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK);
766+
#endif
733767

734768
NVIC_ClearPendingIRQ(RTC_IRQn);
735769

@@ -742,7 +776,7 @@ static int sys_clock_driver_init(void)
742776

743777
int_mask = BIT_MASK(CHAN_COUNT);
744778
if (CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT) {
745-
alloc_mask = BIT_MASK(EXT_CHAN_COUNT) << 1;
779+
alloc_mask = BIT_MASK(EXT_CHAN_COUNT) << (1 + CUSTOM_COUNTER_BIT_WIDTH);
746780
}
747781

748782
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
@@ -761,6 +795,28 @@ static int sys_clock_driver_init(void)
761795
z_nrf_clock_control_lf_on(mode);
762796
#endif
763797

798+
#if CUSTOM_COUNTER_BIT_WIDTH
799+
/* Use channel 1 for wrapping. */
800+
uint8_t chan = 1;
801+
nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan);
802+
nrfx_err_t result;
803+
nrf_ppi_channel_t ch;
804+
805+
nrfy_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan));
806+
nrfy_rtc_cc_set(RTC, chan, COUNTER_MAX);
807+
uint32_t evt_addr;
808+
uint32_t task_addr;
809+
810+
evt_addr = nrfy_rtc_event_address_get(RTC, evt);
811+
task_addr = nrfy_rtc_task_address_get(RTC, NRF_RTC_TASK_CLEAR);
812+
813+
result = nrfx_ppi_channel_alloc(&ch);
814+
if (result != NRFX_SUCCESS) {
815+
return -ENODEV;
816+
}
817+
(void)nrfx_ppi_channel_assign(ch, evt_addr, task_addr);
818+
(void)nrfx_ppi_channel_enable(ch);
819+
#endif
764820
return 0;
765821
}
766822

include/zephyr/drivers/timer/nrf_rtc_timer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extern "C" {
1515

1616
/** @brief Maximum allowed time span that is considered to be in the future.
1717
*/
18-
#define NRF_RTC_TIMER_MAX_SCHEDULE_SPAN BIT(23)
18+
#define NRF_RTC_TIMER_MAX_SCHEDULE_SPAN BIT(CONFIG_NRF_RTC_COUNTER_BIT_WIDTH - 1)
1919

2020
/** @brief RTC timer compare event handler.
2121
*

tests/drivers/timer/nrf_rtc_timer/src/main.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,11 @@ ZTEST(nrf_rtc_timer, test_resetting_cc)
321321
struct test_data test_data = {
322322
.target_time = now + 5,
323323
.window = 0,
324-
.delay = 0,
324+
/* For lower bit width, target_time may be equal to maximum counter value.
325+
* In such case, due to PPI connection clearing the timer, counter value
326+
* read in the handler may be slightly off the set counter value.
327+
*/
328+
.delay = (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < 24) ? 2 : 0,
325329
.err = -EINVAL
326330
};
327331

@@ -361,6 +365,11 @@ static void overflow_sched_handler(int32_t id, uint64_t expire_time,
361365
*/
362366
ZTEST(nrf_rtc_timer, test_overflow)
363367
{
368+
/* For bit width lower than default 24, overflow injection is not possible. */
369+
if (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < 24) {
370+
ztest_test_skip();
371+
}
372+
364373
PRINT("RTC ticks before overflow injection: %u\r\n",
365374
(uint32_t)z_nrf_rtc_timer_read());
366375

0 commit comments

Comments
 (0)