Skip to content

Commit a045993

Browse files
mstasiaknordicrlubos
authored andcommitted
[nrf fromlist] 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. Upstream PR #: 92025 Signed-off-by: Michał Stasiak <[email protected]>
1 parent 7d913ca commit a045993

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

@@ -264,6 +275,15 @@ static int set_alarm(int32_t chan, uint32_t req_cc, bool exact)
264275
*/
265276
enum { MIN_CYCLES_FROM_NOW = 3 };
266277
uint32_t cc_val = req_cc;
278+
279+
#if CUSTOM_COUNTER_BIT_WIDTH
280+
/* If a CC value is 0 when a CLEAR task is set, this will not
281+
* trigger a COMAPRE event. Need to use 1 instead.
282+
*/
283+
if (cc_val % COUNTER_MAX == 0) {
284+
cc_val = 1;
285+
}
286+
#endif
267287
uint32_t cc_inc = MIN_CYCLES_FROM_NOW;
268288

269289
/* Disable event routing for the channel to avoid getting a COMPARE
@@ -427,6 +447,17 @@ uint64_t z_nrf_rtc_timer_read(void)
427447

428448
uint32_t cntr = counter();
429449

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

432463
if (cntr < OVERFLOW_RISK_RANGE_END) {
@@ -565,8 +596,13 @@ void rtc_nrf_isr(const void *arg)
565596
rtc_pretick_rtc1_isr_hook();
566597
}
567598

599+
#if CUSTOM_COUNTER_BIT_WIDTH
600+
if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_COMPARE1_MASK) &&
601+
nrfy_rtc_events_process(RTC, NRF_RTC_INT_COMPARE1_MASK)) {
602+
#else
568603
if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) &&
569604
nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) {
605+
#endif
570606
overflow_cnt++;
571607
}
572608

@@ -625,7 +661,7 @@ int z_nrf_rtc_timer_trigger_overflow(void)
625661
uint64_t now = z_nrf_rtc_timer_read();
626662

627663
if (err == 0) {
628-
sys_clock_timeout_handler(0, now, NULL);
664+
sys_clock_timeout_handler(SYS_CLOCK_CH, now, NULL);
629665
}
630666
bail:
631667
full_int_unlock(mcu_critical_state);
@@ -682,7 +718,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
682718

683719
uint64_t target_time = cyc + last_count;
684720

685-
compare_set(0, target_time, sys_clock_timeout_handler, NULL, false);
721+
compare_set(SYS_CLOCK_CH, target_time, sys_clock_timeout_handler, NULL, false);
686722
}
687723

688724
uint32_t sys_clock_elapsed(void)
@@ -702,7 +738,9 @@ uint32_t sys_clock_cycle_get_32(void)
702738
static void int_event_disable_rtc(void)
703739
{
704740
uint32_t mask = NRF_RTC_INT_TICK_MASK |
741+
#if !CUSTOM_COUNTER_BIT_WIDTH
705742
NRF_RTC_INT_OVERFLOW_MASK |
743+
#endif
706744
NRF_RTC_INT_COMPARE0_MASK |
707745
NRF_RTC_INT_COMPARE1_MASK |
708746
NRF_RTC_INT_COMPARE2_MASK |
@@ -734,7 +772,9 @@ static int sys_clock_driver_init(void)
734772
nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan));
735773
}
736774

775+
#if !CUSTOM_COUNTER_BIT_WIDTH
737776
nrfy_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK);
777+
#endif
738778

739779
NVIC_ClearPendingIRQ(RTC_IRQn);
740780

@@ -747,13 +787,13 @@ static int sys_clock_driver_init(void)
747787

748788
int_mask = BIT_MASK(CHAN_COUNT);
749789
if (CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT) {
750-
alloc_mask = BIT_MASK(EXT_CHAN_COUNT) << 1;
790+
alloc_mask = BIT_MASK(CHAN_COUNT) & ~BIT(SYS_CLOCK_CH);
751791
}
752792

753793
uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
754794
MAX_CYCLES : CYC_PER_TICK;
755795

756-
compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false);
796+
compare_set(SYS_CLOCK_CH, initial_timeout, sys_clock_timeout_handler, NULL, false);
757797

758798
#if defined(CONFIG_CLOCK_CONTROL_NRF)
759799
static const enum nrf_lfclk_start_mode mode =
@@ -766,6 +806,29 @@ static int sys_clock_driver_init(void)
766806
z_nrf_clock_control_lf_on(mode);
767807
#endif
768808

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

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)