Skip to content

Commit 41d56fd

Browse files
mstasiaknordicfabiobaltieri
authored andcommitted
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 <[email protected]>
1 parent 7765485 commit 41d56fd

File tree

4 files changed

+88
-9
lines changed

4 files changed

+88
-9
lines changed

drivers/timer/Kconfig.nrf_rtc

Lines changed: 7 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,10 @@ 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+
range 15 24
51+
4552
endif # NRF_RTC_TIMER

drivers/timer/nrf_rtc_timer.c

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,34 @@
1717
#include <haly/nrfy_rtc.h>
1818
#include <zephyr/irq.h>
1919

20+
#define RTC_BIT_WIDTH 24
21+
22+
#if (CONFIG_NRF_RTC_COUNTER_BIT_WIDTH < RTC_BIT_WIDTH)
23+
#define CUSTOM_COUNTER_BIT_WIDTH 1
24+
#define WRAP_CH 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)
2838
#define RTC_LABEL rtc1
2939
#define CHAN_COUNT_MAX (RTC1_CC_NUM - (RTC_PRETICK ? 1 : 0))
40+
#define SYS_CLOCK_CH 0
3041

3142
BUILD_ASSERT(CHAN_COUNT <= CHAN_COUNT_MAX, "Not enough compare channels");
3243
/* Ensure that counter driver for RTC1 is not enabled. */
3344
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(RTC_LABEL), disabled),
3445
"Counter for RTC1 must be disabled");
3546

36-
#define COUNTER_BIT_WIDTH 24U
47+
#define COUNTER_BIT_WIDTH CONFIG_NRF_RTC_COUNTER_BIT_WIDTH
3748
#define COUNTER_SPAN BIT(COUNTER_BIT_WIDTH)
3849
#define COUNTER_MAX (COUNTER_SPAN - 1U)
3950
#define COUNTER_HALF_SPAN (COUNTER_SPAN / 2U)
@@ -139,7 +150,7 @@ uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan)
139150
{
140151
#if defined(RTC_TASKS_CAPTURE_TASKS_CAPTURE_Msk)
141152
__ASSERT_NO_MSG(chan >= 0 && chan < CHAN_COUNT);
142-
if (chan == 0) {
153+
if (chan == SYS_CLOCK_CH) {
143154
return 0;
144155
}
145156

@@ -259,6 +270,15 @@ static int set_alarm(int32_t chan, uint32_t req_cc, bool exact)
259270
*/
260271
enum { MIN_CYCLES_FROM_NOW = 3 };
261272
uint32_t cc_val = req_cc;
273+
274+
#if CUSTOM_COUNTER_BIT_WIDTH
275+
/* If a CC value is 0 when a CLEAR task is set, this will not
276+
* trigger a COMAPRE event. Need to use 1 instead.
277+
*/
278+
if (cc_val % COUNTER_MAX == 0) {
279+
cc_val = 1;
280+
}
281+
#endif
262282
uint32_t cc_inc = MIN_CYCLES_FROM_NOW;
263283

264284
/* Disable event routing for the channel to avoid getting a COMPARE
@@ -422,6 +442,17 @@ uint64_t z_nrf_rtc_timer_read(void)
422442

423443
uint32_t cntr = counter();
424444

445+
#if CUSTOM_COUNTER_BIT_WIDTH
446+
/* If counter is equal to it maximum value while val is greater
447+
* than anchor, then we can assume that overflow has been recorded
448+
* in the overflow_cnt, but clear task has not been triggered yet.
449+
* Treat counter as if it has been cleared.
450+
*/
451+
if ((cntr == COUNTER_MAX) && (val > anchor)) {
452+
cntr = 0;
453+
}
454+
#endif
455+
425456
val += cntr;
426457

427458
if (cntr < OVERFLOW_RISK_RANGE_END) {
@@ -560,8 +591,13 @@ void rtc_nrf_isr(const void *arg)
560591
rtc_pretick_rtc1_isr_hook();
561592
}
562593

594+
#if CUSTOM_COUNTER_BIT_WIDTH
595+
if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_COMPARE1_MASK) &&
596+
nrfy_rtc_events_process(RTC, NRF_RTC_INT_COMPARE1_MASK)) {
597+
#else
563598
if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) &&
564599
nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) {
600+
#endif
565601
overflow_cnt++;
566602
}
567603

@@ -620,7 +656,7 @@ int z_nrf_rtc_timer_trigger_overflow(void)
620656
uint64_t now = z_nrf_rtc_timer_read();
621657

622658
if (err == 0) {
623-
sys_clock_timeout_handler(0, now, NULL);
659+
sys_clock_timeout_handler(SYS_CLOCK_CH, now, NULL);
624660
}
625661
bail:
626662
full_int_unlock(mcu_critical_state);
@@ -677,7 +713,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
677713

678714
uint64_t target_time = cyc + last_count;
679715

680-
compare_set(0, target_time, sys_clock_timeout_handler, NULL, false);
716+
compare_set(SYS_CLOCK_CH, target_time, sys_clock_timeout_handler, NULL, false);
681717
}
682718

683719
uint32_t sys_clock_elapsed(void)
@@ -697,7 +733,9 @@ uint32_t sys_clock_cycle_get_32(void)
697733
static void int_event_disable_rtc(void)
698734
{
699735
uint32_t mask = NRF_RTC_INT_TICK_MASK |
736+
#if !CUSTOM_COUNTER_BIT_WIDTH
700737
NRF_RTC_INT_OVERFLOW_MASK |
738+
#endif
701739
NRF_RTC_INT_COMPARE0_MASK |
702740
NRF_RTC_INT_COMPARE1_MASK |
703741
NRF_RTC_INT_COMPARE2_MASK |
@@ -729,7 +767,9 @@ static int sys_clock_driver_init(void)
729767
nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan));
730768
}
731769

770+
#if !CUSTOM_COUNTER_BIT_WIDTH
732771
nrfy_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK);
772+
#endif
733773

734774
NVIC_ClearPendingIRQ(RTC_IRQn);
735775

@@ -742,13 +782,13 @@ static int sys_clock_driver_init(void)
742782

743783
int_mask = BIT_MASK(CHAN_COUNT);
744784
if (CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT) {
745-
alloc_mask = BIT_MASK(EXT_CHAN_COUNT) << 1;
785+
alloc_mask = BIT_MASK(CHAN_COUNT) & ~BIT(SYS_CLOCK_CH);
746786
}
747787

748788
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
749789
MAX_CYCLES : CYC_PER_TICK;
750790

751-
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false);
791+
compare_set(SYS_CLOCK_CH, initial_timeout, sys_clock_timeout_handler, NULL, false);
752792

753793
#if defined(CONFIG_CLOCK_CONTROL_NRF)
754794
static const enum nrf_lfclk_start_mode mode =
@@ -761,6 +801,29 @@ static int sys_clock_driver_init(void)
761801
z_nrf_clock_control_lf_on(mode);
762802
#endif
763803

804+
#if CUSTOM_COUNTER_BIT_WIDTH
805+
/* WRAP_CH reserved for wrapping. */
806+
alloc_mask &= ~BIT(WRAP_CH);
807+
808+
nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(WRAP_CH);
809+
nrfx_err_t result;
810+
nrf_ppi_channel_t ch;
811+
812+
nrfy_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(WRAP_CH));
813+
nrfy_rtc_cc_set(RTC, WRAP_CH, COUNTER_MAX);
814+
uint32_t evt_addr;
815+
uint32_t task_addr;
816+
817+
evt_addr = nrfy_rtc_event_address_get(RTC, evt);
818+
task_addr = nrfy_rtc_task_address_get(RTC, NRF_RTC_TASK_CLEAR);
819+
820+
result = nrfx_ppi_channel_alloc(&ch);
821+
if (result != NRFX_SUCCESS) {
822+
return -ENODEV;
823+
}
824+
(void)nrfx_ppi_channel_assign(ch, evt_addr, task_addr);
825+
(void)nrfx_ppi_channel_enable(ch);
826+
#endif
764827
return 0;
765828
}
766829

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)