1 /*
2 * Copyright (c) 2017 Oticon A/S
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * RTC - Real-time counter
10 *
11 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/rtc.html?cp=5_1_0_5_19
12 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/rtc.html?cp=4_0_0_6_27
13 */
14
15 /*
16 * This file provides the implementation of the RTC peripherals,
17 * and instantiates N of them, as described in the configuration (NHW_config.h)
18 *
19 * Notes:
20 *
21 * * TICK events are NOT modeled
22 *
23 * * The COUNTER register is only updated when read with the proper HAL function
24 *
25 * * Unlike the real HW, there is no jitter or (variable) delay in the tasks/events,
26 * operations, or synchronization of configuration:
27 * * Triggering a task (Thru the PPI or register write) starts the operation
28 * immediately (in HW it takes between 1/2 and 1+1/2 LFCLKs:
29 * "CLEAR and STOP and TRIGOVRFLW [..] will be delayed as long as it
30 * takes for the peripheral to clock a falling edge and a rising edge of the LFCLK.")
31 * * Events and interrupts are raised immediately once produced (in real HW
32 * they can be raised relatively at +-1/2 LFCLK or +-1/2 PCLK16M of each other)
33 * (In real HW this is due to the 32K-16M clock domain crossing synchronization)
34 * * A STOP task stops the counter immediately.
35 *
36 * * As the CLEAR task does not have delay, a SHORT of COMPARE<n>_CLEAR will cause the
37 * CLEAR to be instantaneous.
38 * While in the real HW, as per the spec:
39 * "If the COMPARE[i]_CLEAR short is enabled, the COUNTER will be cleared
40 * *one LFClk after* the COMPARE event"
41 *
42 * * Unlike in real HW reading the COUNTER register is instantaneous (in real HW
43 * it takes up to 6 PCLK16M cycles, during which the CPU is stalled.
44 *
45 * * Writing to the PRESCALER register when the RTC is running is not prevented
46 * (unlike in real HW), but doing so can have unintended consequences.
47 * Though the PRESCALER is shadowed into an internal register on the tasks
48 * START, CLEAR, and TRIGOVRFLW as per the spec.
49 *
50 * * Note, in nrf52 devices, the spec seems to confusingly state that the LFCLK
51 * clock must be ready before the RTC can be used, yet that a TRIGOVRFLW task
52 * will get the RTC to request the LFClock.
53 * But in real life (and the model) it seems no task will automatically
54 * request the clock.
55 * For nrf5340 devices, TRIGOVRFLW does not seem to request the CLOCK either,
56 * but START seems to as per the spec.
57 *
58 * * Note this model does not yet automatically request the LFCLK (for a nRF5340)
59 * with task START
60 *
61 * * This models assumes that once the LFCLK is started it is never stopped.
62 *
63 * * Note that, just like for the real RTC, the event generation logic is slightly
64 * different than for other peripherals
65 *
66 * Implementation notes:
67 * In a naive (but very simple) implementation the RTC model could be called
68 * every LFCLK tick. But this would be really slow (as we'd need to call it 32768
69 * times per second).
70 * Instead this model checks ahead, when the next compare or overflow event would
71 * trigger and sets a timer for its callback.
72 * There is one common timer exposed to the HW scheduler, and a set of internal timers
73 * per RTC instance (one per CC register, and one for the counter overflow)
74 *
75 * The RTC keeps track internally of the time with submicrosecond resolution
76 * (9 decimal bits) to have a exact representation of the LF clock ticks,
77 * and avoid accumulating rounding errors.
78 * With this current implementation, the maximum runtime of the RTC is limited to
79 * 2**64/2**9 microseconds from boot (~1142 years)
80 *
81 *
82 * Pending to implement:
83 * * TICK events
84 *
85 * * Delay of TASKs CLEAR, STOP and TRIGOVRFLW
86 *
87 * * For nrf5340: With task START, the RTC should automatically request the LFCLK source with RC oscillator if the LFCLK is not already running.
88 */
89
90 #include <string.h>
91 #include <stdbool.h>
92 #include <stdint.h>
93 #include "bs_tracing.h"
94 #include "bs_oswrap.h"
95 #include "nsi_hw_scheduler.h"
96 #include "nsi_tasks.h"
97 #include "nsi_hws_models_if.h"
98 #include "NHW_common_types.h"
99 #include "NHW_config.h"
100 #include "NHW_peri_types.h"
101 #include "NHW_xPPI.h"
102 #include "NHW_CLOCK.h"
103 #include "irq_ctrl.h"
104 #include "NHW_RTC.h"
105
106 #define RTC_COUNTER_MASK 0xFFFFFF /*24 bits*/
107 #define RTC_TRIGGER_OVERFLOW_COUNTER_VALUE 0xFFFFF0
108
109 #define SUB_US_BITS 9 // Bits representing sub-microsecond units
110
111 #define LF_CLOCK_PERIOD_subus 15625 /*in a fixed point format with 9 bits per us, the LF clock period*/
112 #define LF_CLOCK_PERIOD_us 31 /* the LF clock period in us ceil(1e6/32768) = ceil(30.517578125us) */
113
114 struct rtc_status {
115 NRF_RTC_Type *NRF_RTC_regs;
116
117 int n_CCs; //Number of compare/capture registers in this rtc instance
118
119 bs_time_t *cc_timers; //[n_CCs] When each CC will match (in microseconds)
120 bs_time_t overflow_timer; // When the timer will overflow (in microseconds)
121 uint64_t overflow_timer_sub_us; // When the timer will overflow (in sub-microsecond units)
122
123 uint64_t counter_startT_sub_us; //Time when the counter was "started" (really the time that would correspond to COUNTER = 0)
124 uint64_t counter_startT_negative_sub_us;
125
126 uint32_t counter_at_stop; //Internal counter value when the counter was *stopped*
127
128 uint32_t INTEN;
129 uint32_t PRESC;
130 bool running; // Is this RTC running/started
131
132 #if (NHW_HAS_DPPI)
133 uint dppi_map; //To which DPPI instance are this RTC subscribe&publish ports connected to
134 struct nhw_subsc_mem* subscribed_CAPTURE; //[n_CCs]
135 struct nhw_subsc_mem subscribed_START;
136 struct nhw_subsc_mem subscribed_STOP;
137 struct nhw_subsc_mem subscribed_CLEAR;
138 struct nhw_subsc_mem subscribed_TRIGOVRFLW;
139 #endif
140 };
141
142 static uint64_t first_lf_tick_time_sub_us;
143
144 static bs_time_t Timer_RTC = TIME_NEVER;
145 static struct rtc_status nhw_rtc_st[NHW_RTC_TOTAL_INST];
146 NRF_RTC_Type NRF_RTC_regs[NHW_RTC_TOTAL_INST];
147
148 static bs_time_t sub_us_time_to_us_time(uint64_t sub_us_time);
149 static uint64_t us_time_to_sub_us_time(bs_time_t us_time);
150 static void nhw_rtc_TASKS_CLEAR(uint rtc);
151 static void nhw_rtc_signal_OVERFLOW(uint rtc);
152 static void nhw_rtc_signal_COMPARE(uint rtc, uint cc);
153
nhw_rtc_init(void)154 static void nhw_rtc_init(void) {
155 #if (NHW_HAS_DPPI)
156 /* Mapping of peripheral instance to DPPI instance */
157 uint nhw_rtc_dppi_map[NHW_RTC_TOTAL_INST] = NHW_RTC_DPPI_MAP;
158 #endif
159 int RTC_n_CCs[NHW_RTC_TOTAL_INST] = NHW_RTC_N_CC;
160
161 memset(NRF_RTC_regs, 0, sizeof(NRF_RTC_regs));
162
163 for (int i = 0; i < NHW_RTC_TOTAL_INST ; i++) {
164 struct rtc_status *rtc_st = &nhw_rtc_st[i];
165
166 rtc_st->NRF_RTC_regs = &NRF_RTC_regs[i];
167 rtc_st->n_CCs = RTC_n_CCs[i];
168
169 rtc_st->counter_startT_sub_us = TIME_NEVER;
170
171 rtc_st->cc_timers = (bs_time_t *)bs_malloc(sizeof(bs_time_t)*RTC_n_CCs[i]);
172
173 for (int j = 0 ; j < rtc_st->n_CCs ; j++) {
174 rtc_st->cc_timers[j] = TIME_NEVER;
175 }
176 rtc_st->overflow_timer = TIME_NEVER;
177 rtc_st->overflow_timer_sub_us = TIME_NEVER;
178
179 #if (NHW_HAS_DPPI)
180 rtc_st->dppi_map = nhw_rtc_dppi_map[i];
181 rtc_st->subscribed_CAPTURE = (struct nhw_subsc_mem*)bs_calloc(RTC_n_CCs[i], sizeof(struct nhw_subsc_mem));
182 #endif
183 }
184 Timer_RTC = TIME_NEVER;
185 }
186
187 NSI_TASK(nhw_rtc_init, HW_INIT, 100);
188
189 /*
190 * Free all RTC instances resources before program exit
191 */
nhw_rtc_free(void)192 static void nhw_rtc_free(void)
193 {
194 for (int t = 0; t < NHW_RTC_TOTAL_INST; t++) {
195 struct rtc_status *rtc_st = &nhw_rtc_st[t];
196
197 free(rtc_st->cc_timers);
198 rtc_st->cc_timers = NULL;
199
200 #if (NHW_HAS_DPPI)
201 free(rtc_st->subscribed_CAPTURE);
202 rtc_st->subscribed_CAPTURE = NULL;
203 #endif /* (NHW_HAS_DPPI) */
204 }
205 }
206
207 NSI_TASK(nhw_rtc_free, ON_EXIT_PRE, 100);
208
209 /**
210 * Convert a time delta in sub-microseconds units to the equivalent time in microseconds.
211 * The value is always rounded UP. This is because otherwise events would be registered
212 * in a time in microseconds before the event actually occurred. This would lead to many imprecise
213 * event timings for example if the timing of an event would be calculated base on the last LF
214 * clock tick (which happens for example when triggering the CLEAR or TRIGGER_OVERFLOW tasks)
215 */
sub_us_time_to_us_time(uint64_t sub_us_time)216 static bs_time_t sub_us_time_to_us_time(uint64_t sub_us_time)
217 {
218 bs_time_t us_time = sub_us_time >> SUB_US_BITS;
219
220 if(sub_us_time % (1U << SUB_US_BITS) != 0) //rounding up
221 {
222 us_time += 1;
223 }
224
225 return us_time;
226 }
227
228 /**
229 * Convert a time delta in microseconds to the equivalent time in sub-microseconds units
230 */
us_time_to_sub_us_time(bs_time_t us_time)231 static uint64_t us_time_to_sub_us_time(bs_time_t us_time)
232 {
233 return us_time << SUB_US_BITS;
234 }
235
get_time_in_sub_us(void)236 static uint64_t get_time_in_sub_us(void)
237 {
238 bs_time_t now = nsi_hws_get_time();
239
240 if (now >= sub_us_time_to_us_time(TIME_NEVER)) {
241 bs_trace_error_time_line("Bummer, the RTC model only supports running for 1142 years\n");
242 /*If you really need this, generalize the calculation to more than 64 bits*/
243 }
244
245 return us_time_to_sub_us_time(now);
246 }
247
get_last_lf_tick_time_sub_us(void)248 static uint64_t get_last_lf_tick_time_sub_us(void) {
249 uint64_t now_sub_us = get_time_in_sub_us();
250
251 uint64_t n_lf_ticks = (now_sub_us - first_lf_tick_time_sub_us) / LF_CLOCK_PERIOD_subus; //floor()
252 uint64_t last_tick_time_sub_us = n_lf_ticks * LF_CLOCK_PERIOD_subus;
253 last_tick_time_sub_us += first_lf_tick_time_sub_us;
254
255 return last_tick_time_sub_us;
256 }
257
258 /**
259 * Convert a time delta in sub-microsecond units to the equivalent count accounting for the PRESCALER
260 * Note that the number is rounded down [floor()]
261 */
time_sub_us_to_counter(uint rtc,uint64_t delta_sub_us)262 static uint64_t time_sub_us_to_counter(uint rtc, uint64_t delta_sub_us) {
263 uint64_t ticks;
264
265 ticks = delta_sub_us / ((uint64_t)LF_CLOCK_PERIOD_subus * (nhw_rtc_st[rtc].PRESC + 1));
266 return ticks;
267 }
268
269 /**
270 * Convert a counter delta to sub-microsecond units accounting for the PRESCALER
271 */
counter_to_time_sub_us(uint rtc,uint64_t counter)272 static uint64_t counter_to_time_sub_us(uint rtc, uint64_t counter) {
273 uint64_t Elapsed;
274
275 Elapsed = counter * (uint64_t)LF_CLOCK_PERIOD_subus * (nhw_rtc_st[rtc].PRESC + 1);
276
277 return Elapsed;
278 }
279
280 /**
281 * Return the time in sub-microsecond units it takes for the COUNTER to do 1 wrap
282 */
time_of_1_counter_wrap_sub_us(uint rtc)283 static uint64_t time_of_1_counter_wrap_sub_us(uint rtc) {
284 return counter_to_time_sub_us(rtc, (uint64_t)RTC_COUNTER_MASK + 1);
285 }
286
287 /*
288 * Return the *next* time (in us) when the RTC counter will reach <counter_match>
289 */
get_counter_match_time(uint rtc,uint64_t counter_match,uint64_t * next_match_sub_us)290 static bs_time_t get_counter_match_time(uint rtc, uint64_t counter_match, uint64_t* next_match_sub_us)
291 {
292 struct rtc_status *this = &nhw_rtc_st[rtc];
293
294 bs_time_t next_match_us = TIME_NEVER;
295 *next_match_sub_us = TIME_NEVER;
296
297 if (this->running == true) {
298 uint64_t now_sub_us = get_time_in_sub_us();
299 uint64_t counter_match_sub_us = counter_to_time_sub_us(rtc, counter_match);
300
301 if(this->counter_startT_sub_us > 0)
302 {
303 *next_match_sub_us = this->counter_startT_sub_us
304 + counter_match_sub_us;
305 }
306 else if (counter_match_sub_us > this->counter_startT_negative_sub_us)
307 {
308 *next_match_sub_us = counter_match_sub_us - this->counter_startT_negative_sub_us;
309 }
310 else
311 {
312 *next_match_sub_us = time_of_1_counter_wrap_sub_us(rtc)
313 + counter_match_sub_us - this->counter_startT_negative_sub_us;
314 }
315
316 while(*next_match_sub_us <= now_sub_us)
317 {
318 *next_match_sub_us += time_of_1_counter_wrap_sub_us(rtc);
319 }
320
321 next_match_us = sub_us_time_to_us_time(*next_match_sub_us);
322 }
323
324 return next_match_us;
325 }
326
nhw_rtc_update_master_timer(void)327 static void nhw_rtc_update_master_timer(void) {
328 Timer_RTC = TIME_NEVER;
329 for (int rtc = 0; rtc < NHW_RTC_TOTAL_INST ; rtc++) {
330 struct rtc_status *this = &nhw_rtc_st[rtc];
331
332 if (this->running == false) {
333 continue;
334 }
335 for (int cc = 0 ; cc < this->n_CCs ; cc++) {
336 if (this->cc_timers[cc] < Timer_RTC) {
337 Timer_RTC = this->cc_timers[cc];
338 }
339 }
340
341 if (this->overflow_timer < Timer_RTC) {
342 Timer_RTC = this->overflow_timer;
343 }
344 }
345 nsi_hws_find_next_event();
346 }
347
348 /**
349 * Save in cc_timers[cc] the *next* time when this RTC will match the
350 * CC[cc] register
351 */
update_cc_timer(uint rtc,uint cc)352 static void update_cc_timer(uint rtc, uint cc) {
353 uint64_t match_sub_us; // Only to comply to the interface
354 nhw_rtc_st[rtc].cc_timers[cc] = get_counter_match_time(rtc, NRF_RTC_regs[rtc].CC[cc], &match_sub_us);
355 }
356
357 /*
358 * Update all cc_timers[*] for a RTC instance
359 * to the *next* time when they will match
360 */
update_all_cc_timers(uint rtc)361 static void update_all_cc_timers(uint rtc) {
362 for (int cc = 0 ; cc < nhw_rtc_st[rtc].n_CCs; cc++) {
363 update_cc_timer(rtc, cc);
364 }
365 }
366
update_overflow_timer(uint rtc)367 static void update_overflow_timer(uint rtc) {
368 struct rtc_status *this = &nhw_rtc_st[rtc];
369 this->overflow_timer = get_counter_match_time(rtc, RTC_COUNTER_MASK + 1, &this->overflow_timer_sub_us);
370 }
371
update_timers(int rtc)372 static void update_timers(int rtc)
373 {
374 update_all_cc_timers(rtc);
375 update_overflow_timer(rtc);
376 nhw_rtc_update_master_timer();
377 }
378
379 /**
380 * Sets the internal state of the counter like if the counter was just set to the specified value.
381 * This is done by setting the "counter start time"
382 * (counter_startT*) to an appropriate value, so that the time elapsed from the counter start
383 * corresponds to the given counter value. Such virtual "counter start time" can be negative.
384 */
nhw_rtc_set_counter(uint rtc,uint64_t counter_val)385 static void nhw_rtc_set_counter(uint rtc, uint64_t counter_val)
386 {
387 struct rtc_status *this = &nhw_rtc_st[rtc];
388
389 counter_val &= RTC_COUNTER_MASK;
390 uint64_t counter_val_sub_us = counter_to_time_sub_us(rtc, counter_val);
391
392 // All the functions which use this reset the <PRESC>, so it is like the counter was set
393 // on the last LF clock tick
394 uint64_t last_lf_tick_sub_us = get_last_lf_tick_time_sub_us();
395
396 if(last_lf_tick_sub_us >= counter_val_sub_us)
397 {
398 this->counter_startT_sub_us = last_lf_tick_sub_us - counter_val_sub_us;
399 this->counter_startT_negative_sub_us = 0;
400 }
401 else
402 {
403 this->counter_startT_sub_us = 0;
404 this->counter_startT_negative_sub_us = counter_val_sub_us - last_lf_tick_sub_us;
405 }
406
407 NRF_RTC_regs[rtc].COUNTER = counter_val;
408
409 update_timers(rtc);
410 }
411
handle_overflow_event(uint rtc)412 static void handle_overflow_event(uint rtc)
413 {
414 struct rtc_status *this = &nhw_rtc_st[rtc];
415
416 // The real time (in sub-microsecond units, not in microseconds)
417 // in which the current overflow event occurs.
418 // update_overflow_timer will overwrite overflow_timer_sub_us[rtc]
419 uint64_t current_overflow_event_sub_us = this->overflow_timer_sub_us;
420
421 update_overflow_timer(rtc); //Next time it will overflow
422
423 bs_trace_raw_time(8, "RTC%i: Timer overflow\n", rtc);
424
425 this->counter_startT_sub_us = current_overflow_event_sub_us;
426 this->counter_startT_negative_sub_us = 0;
427
428 nhw_rtc_signal_OVERFLOW(rtc);
429 }
430
nhw_rtc_timer_triggered(void)431 static void nhw_rtc_timer_triggered(void) {
432 for (int rtc = 0; rtc < NHW_RTC_TOTAL_INST ; rtc++) {
433 struct rtc_status *rtc_el = &nhw_rtc_st[rtc];
434 if (rtc_el->running == false) {
435 continue;
436 }
437
438 for (int cc = 0 ; cc < rtc_el->n_CCs ; cc++) {
439 if (rtc_el->cc_timers[cc] == Timer_RTC ){ //This CC is matching now
440 update_cc_timer(rtc, cc); //Next time it will match
441 nhw_rtc_signal_COMPARE(rtc, cc);
442 }
443 }
444
445 if (rtc_el->overflow_timer == Timer_RTC) { //Overflow occurred now
446 handle_overflow_event(rtc); // this must always be the last event, as it might update counter_startT_sub_us
447 }
448
449 }
450 nhw_rtc_update_master_timer();
451 }
452
453 NSI_HW_EVENT(Timer_RTC, nhw_rtc_timer_triggered, 50);
454
455 /**
456 * Check if an EVTEN or INTEN has the tick event set
457 */
check_not_supported_TICK(uint32_t i)458 static void check_not_supported_TICK(uint32_t i) {
459 if (i & RTC_EVTEN_TICK_Msk) {
460 bs_trace_warning_line_time("RTC: The TICK functionality is not modelled\n");
461 }
462 }
463
nhw_rtc_notify_first_lf_tick(void)464 void nhw_rtc_notify_first_lf_tick(void) {
465 first_lf_tick_time_sub_us = get_time_in_sub_us();
466 bs_trace_raw_time(9, "RTC: First lf tick\n");
467 }
468
469 /*
470 * Update the counter register so it can be read by SW
471 */
nhw_rtc_update_COUNTER(uint rtc)472 void nhw_rtc_update_COUNTER(uint rtc) {
473 struct rtc_status *this = &nhw_rtc_st[rtc];
474 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
475
476 if (this->running == true) {
477 uint64_t count;
478 count = time_sub_us_to_counter(rtc,
479 get_time_in_sub_us() - this->counter_startT_sub_us
480 + this->counter_startT_negative_sub_us);
481 RTC_regs->COUNTER = count & RTC_COUNTER_MASK;
482 } else {
483 RTC_regs->COUNTER = this->counter_at_stop & RTC_COUNTER_MASK;
484 }
485 }
486
487 /**
488 * TASK_START triggered handler
489 */
nhw_rtc_TASKS_START(uint rtc)490 static void nhw_rtc_TASKS_START(uint rtc) {
491 struct rtc_status *this = &nhw_rtc_st[rtc];
492
493 if (this->running == true) {
494 return;
495 }
496 bs_trace_raw_time(5, "RTC%i: TASK_START\n", rtc);
497 this->running = true;
498
499 /* Pre-scaler value is latched to an internal register on tasks START, CLEAR, and TRIGOVRFLW */
500 this->PRESC = NRF_RTC_regs[rtc].PRESCALER;
501
502 //If the counter is not zero at start, is like if the counter was started earlier
503 nhw_rtc_set_counter(rtc, this->counter_at_stop);
504 }
505
506 /**
507 * TASK_STOP triggered handler
508 */
nhw_rtc_TASKS_STOP(uint rtc)509 static void nhw_rtc_TASKS_STOP(uint rtc) {
510 struct rtc_status *this = &nhw_rtc_st[rtc];
511
512 if (this->running == false) {
513 return;
514 }
515 bs_trace_raw_time(5, "RTC%i: TASK_STOP\n", rtc);
516 this->running = false;
517 this->counter_at_stop = time_sub_us_to_counter(rtc,
518 get_time_in_sub_us() - this->counter_startT_sub_us
519 + this->counter_startT_negative_sub_us); //we save the value when the counter was stoped in case it is started again without clearing it
520 this->counter_at_stop &= RTC_COUNTER_MASK;
521 NRF_RTC_regs[rtc].COUNTER = this->counter_at_stop;
522 for (int cc = 0 ; cc < this->n_CCs ; cc++) {
523 this->cc_timers[cc] = TIME_NEVER;
524 }
525 this->overflow_timer = TIME_NEVER;
526 nhw_rtc_update_master_timer();
527 }
528
529 /**
530 * TASK_CLEAR triggered handler
531 */
nhw_rtc_TASKS_CLEAR(uint rtc)532 static void nhw_rtc_TASKS_CLEAR(uint rtc) {
533 bs_trace_raw_time(5, "RTC%i: TASK_CLEAR\n", rtc);
534
535 /* Pre-scaler value is latched to an internal register on tasks START, CLEAR, and TRIGOVRFLW */
536 nhw_rtc_st[rtc].PRESC = NRF_RTC_regs[rtc].PRESCALER;
537 nhw_rtc_st[rtc].counter_at_stop = 0;
538 nhw_rtc_set_counter(rtc, 0);
539 }
540
541 /**
542 * TASK_TRIGGER_OVERFLOW triggered handler
543 */
nhw_rtc_TASKS_TRIGOVRFLW(uint rtc)544 static void nhw_rtc_TASKS_TRIGOVRFLW(uint rtc) {
545
546 bs_trace_raw_time(5, "RTC%i: TASK_TRIGGER_OVERFLOW\n", rtc);
547
548 /* Pre-scaler value is latched to an internal register on tasks START, CLEAR, and TRIGOVRFLW */
549 nhw_rtc_st[rtc].PRESC = NRF_RTC_regs[rtc].PRESCALER;
550 nhw_rtc_st[rtc].counter_at_stop = RTC_TRIGGER_OVERFLOW_COUNTER_VALUE;
551 nhw_rtc_set_counter(rtc, RTC_TRIGGER_OVERFLOW_COUNTER_VALUE);
552 }
553
554 #if (NHW_RTC_HAS_CAPTURE)
nhw_rtc_TASKS_CAPTURE(uint rtc,uint cc_n)555 static void nhw_rtc_TASKS_CAPTURE(uint rtc, uint cc_n) {
556 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
557
558 nhw_rtc_update_COUNTER(rtc);
559 RTC_regs->CC[cc_n] = RTC_regs->COUNTER;
560
561 nhw_rtc_regw_sideeffects_CC(rtc, cc_n);
562 }
563 #endif /* NHW_RTC_HAS_CAPTURE */
564
nhw_rtc_eval_interrupts(uint rtc)565 static void nhw_rtc_eval_interrupts(uint rtc) {
566 /* Mapping of peripheral instance to {int controller instance, int number} */
567 static struct nhw_irq_mapping nhw_rtc_irq_map[NHW_RTC_TOTAL_INST] = NHW_RTC_INT_MAP;
568 static bool RTC_int_line[NHW_RTC_TOTAL_INST]; /* Is the RTC currently driving its interrupt line high */
569
570 struct rtc_status *this = &nhw_rtc_st[rtc];
571 bool new_int_line = false;
572
573 for (int cc = 0; cc < this->n_CCs; cc++) {
574 int mask = this->INTEN & (RTC_INTENSET_COMPARE0_Msk << cc);
575 if (NRF_RTC_regs[rtc].EVENTS_COMPARE[cc] && mask) {
576 new_int_line = true;
577 break; /* No need to check more */
578 }
579 }
580
581 if (NRF_RTC_regs[rtc].EVENTS_TICK && (this->INTEN & RTC_INTENSET_TICK_Msk)) {
582 new_int_line = true;
583 }
584 if (NRF_RTC_regs[rtc].EVENTS_OVRFLW && (this->INTEN & RTC_INTENSET_OVRFLW_Msk)) {
585 new_int_line = true;
586 }
587
588 if (RTC_int_line[rtc] == false && new_int_line == true) {
589 RTC_int_line[rtc] = true;
590 hw_irq_ctrl_raise_level_irq_line(nhw_rtc_irq_map[rtc].cntl_inst,
591 nhw_rtc_irq_map[rtc].int_nbr);
592 } else if (RTC_int_line[rtc] == true && new_int_line == false) {
593 RTC_int_line[rtc] = false;
594
595 hw_irq_ctrl_lower_level_irq_line(nhw_rtc_irq_map[rtc].cntl_inst,
596 nhw_rtc_irq_map[rtc].int_nbr);
597 }
598 }
599
nhw_rtc_signal_COMPARE(uint rtc,uint cc)600 static void nhw_rtc_signal_COMPARE(uint rtc, uint cc)
601 {
602 struct rtc_status *this = &nhw_rtc_st[rtc];
603 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
604
605 #if (NHW_RTC_HAS_SHORT_COMP_CLEAR)
606 if (RTC_regs->SHORTS & (RTC_SHORTS_COMPARE0_CLEAR_Msk << cc)) {
607 nhw_rtc_TASKS_CLEAR(rtc);
608 bs_trace_warning_line_time("RTC: COMPARE->CLEAR short used, but CLEAR is instantaneous."
609 "If you are using this to generate a periodic interrupt, the period"
610 "will be 1 count too short\n");
611 }
612 #endif /* NHW_RTC_HAS_SHORT_COMP_CLEAR */
613
614 uint32_t mask = RTC_EVTEN_COMPARE0_Msk << cc;
615
616 if (!((RTC_regs->EVTEN | this->INTEN) & mask)) {
617 return;
618 }
619
620 RTC_regs->EVENTS_COMPARE[cc] = 1;
621
622 if (RTC_regs->EVTEN & mask) {
623 #if (NHW_HAS_PPI)
624 ppi_event_types_t event = RTC0_EVENTS_COMPARE_0;
625 switch (rtc){
626 case 0:
627 event = RTC0_EVENTS_COMPARE_0;
628 break;
629 case 1:
630 event = RTC1_EVENTS_COMPARE_0;
631 break;
632 case 2:
633 event = RTC2_EVENTS_COMPARE_0;
634 break;
635 }
636 event += cc;
637 nrf_ppi_event(event);
638 #elif (NHW_HAS_DPPI)
639 nhw_dppi_event_signal_if(this->dppi_map,
640 RTC_regs->PUBLISH_COMPARE[cc]);
641 #endif
642 }
643
644 nhw_rtc_eval_interrupts(rtc);
645 }
646
nhw_rtc_signal_OVERFLOW(uint rtc)647 static void nhw_rtc_signal_OVERFLOW(uint rtc)
648 {
649 struct rtc_status *this = &nhw_rtc_st[rtc];
650 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
651
652 if (!((RTC_regs->EVTEN | this->INTEN) & RTC_EVTEN_OVRFLW_Msk)) {
653 return;
654 }
655
656 RTC_regs->EVENTS_OVRFLW = 1;
657
658 if (RTC_regs->EVTEN & RTC_EVTEN_OVRFLW_Msk) {
659 #if (NHW_HAS_PPI)
660 ppi_event_types_t event = RTC0_EVENTS_OVRFLW;
661 switch (rtc){
662 case 0:
663 event = RTC0_EVENTS_OVRFLW;
664 break;
665 case 1:
666 event = RTC1_EVENTS_OVRFLW;
667 break;
668 case 2:
669 event = RTC2_EVENTS_OVRFLW;
670 break;
671 }
672 nrf_ppi_event(event);
673 #elif (NHW_HAS_DPPI)
674 nhw_dppi_event_signal_if(this->dppi_map,
675 RTC_regs->PUBLISH_OVRFLW);
676 #endif
677 }
678
679 nhw_rtc_eval_interrupts(rtc);
680 }
681
682
nhw_rtc_signal_TICK(uint rtc)683 /*static*/ void nhw_rtc_signal_TICK(uint rtc) /*Not yet used, as all TICK functionality is not yet implemented */
684 {
685 struct rtc_status *this = &nhw_rtc_st[rtc];
686 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
687
688 if (!((RTC_regs->EVTEN | this->INTEN) & RTC_EVTEN_TICK_Msk)) {
689 return;
690 }
691
692 RTC_regs->EVENTS_TICK = 1;
693
694 if (RTC_regs->EVTEN & RTC_EVTEN_TICK_Msk) {
695 #if (NHW_HAS_PPI)
696 ppi_event_types_t event = RTC0_EVENTS_TICK;
697 switch (rtc){
698 case 0:
699 event = RTC0_EVENTS_TICK;
700 break;
701 case 1:
702 event = RTC1_EVENTS_TICK;
703 break;
704 case 2:
705 event = RTC2_EVENTS_TICK;
706 break;
707 }
708 nrf_ppi_event(event);
709 #elif (NHW_HAS_DPPI)
710 nhw_dppi_event_signal_if(this->dppi_map,
711 RTC_regs->PUBLISH_TICK);
712 #endif
713 }
714
715 nhw_rtc_eval_interrupts(rtc);
716 }
717
nhw_rtc_regw_sideeffect_TASKS_START(uint i)718 void nhw_rtc_regw_sideeffect_TASKS_START(uint i) {
719 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
720
721 if (RTC_regs->TASKS_START) {
722 RTC_regs->TASKS_START = 0;
723 nhw_rtc_TASKS_START(i);
724 }
725 }
726
nhw_rtc_regw_sideeffect_TASKS_STOP(uint i)727 void nhw_rtc_regw_sideeffect_TASKS_STOP(uint i) {
728 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
729
730 if (RTC_regs->TASKS_STOP) {
731 RTC_regs->TASKS_STOP = 0;
732 nhw_rtc_TASKS_STOP(i);
733 }
734 }
735
nhw_rtc_regw_sideeffect_TASKS_CLEAR(uint i)736 void nhw_rtc_regw_sideeffect_TASKS_CLEAR(uint i) {
737 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
738
739 if (RTC_regs->TASKS_CLEAR) {
740 RTC_regs->TASKS_CLEAR = 0;
741 nhw_rtc_TASKS_CLEAR(i);
742 }
743 }
744
nhw_rtc_regw_sideeffect_TASKS_TRIGOVRFLW(uint i)745 void nhw_rtc_regw_sideeffect_TASKS_TRIGOVRFLW(uint i) {
746 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
747
748 if (RTC_regs->TASKS_TRIGOVRFLW) {
749 RTC_regs->TASKS_TRIGOVRFLW = 0;
750 nhw_rtc_TASKS_TRIGOVRFLW(i);
751 }
752 }
753
754 #if (NHW_RTC_HAS_CAPTURE)
nhw_rtc_regw_sideeffect_TASKS_CAPTURE(uint i,uint cc)755 void nhw_rtc_regw_sideeffect_TASKS_CAPTURE(uint i, uint cc) {
756 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
757
758 if (RTC_regs->TASKS_CAPTURE[cc]) {
759 RTC_regs->TASKS_CAPTURE[cc] = 0;
760 nhw_rtc_TASKS_CAPTURE(i, cc);
761 }
762 }
763 #endif /* NHW_RTC_HAS_CAPTURE */
764
765 #if (NHW_HAS_DPPI)
766
nhw_rtc_taskcapture_wrap(void * param)767 static void nhw_rtc_taskcapture_wrap(void* param) {
768 unsigned int inst = (uintptr_t)param >> 16;
769 uint cc_n = (uintptr_t)param & 0xFFFF;
770 nhw_rtc_TASKS_CAPTURE(inst, cc_n);
771 }
772
nhw_rtc_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst,uint cc_n)773 void nhw_rtc_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst, uint cc_n) {
774 struct rtc_status *this = &nhw_rtc_st[inst];
775
776 nhw_dppi_common_subscribe_sideeffect(this->dppi_map,
777 this->NRF_RTC_regs->SUBSCRIBE_CAPTURE[cc_n],
778 &this->subscribed_CAPTURE[cc_n],
779 nhw_rtc_taskcapture_wrap,
780 (void*)((inst << 16) + cc_n));
781 }
782
783 #define NHW_RTC_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N) \
784 static void nhw_rtc_task##TASK_N##_wrap(void* param) \
785 { \
786 nhw_rtc_TASKS_##TASK_N((int) param); \
787 } \
788 \
789 void nhw_rtc_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst) \
790 { \
791 struct rtc_status *this = &nhw_rtc_st[inst]; \
792 \
793 nhw_dppi_common_subscribe_sideeffect(this->dppi_map, \
794 this->NRF_RTC_regs->SUBSCRIBE_##TASK_N, \
795 &this->subscribed_##TASK_N, \
796 nhw_rtc_task##TASK_N##_wrap, \
797 (void*) inst); \
798 }
799
800 NHW_RTC_REGW_SIDEFFECTS_SUBSCRIBE(START)
NHW_RTC_REGW_SIDEFFECTS_SUBSCRIBE(STOP)801 NHW_RTC_REGW_SIDEFFECTS_SUBSCRIBE(STOP)
802 NHW_RTC_REGW_SIDEFFECTS_SUBSCRIBE(CLEAR)
803 NHW_RTC_REGW_SIDEFFECTS_SUBSCRIBE(TRIGOVRFLW)
804
805 #endif /* NHW_HAS_DPPI */
806
807 void nhw_rtc_regw_sideeffect_INTENSET(uint rtc)
808 {
809 struct rtc_status *this = &nhw_rtc_st[rtc];
810 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
811
812 if ( RTC_regs->INTENSET ){
813 this->INTEN |= RTC_regs->INTENSET;
814 RTC_regs->INTENSET = this->INTEN;
815
816 check_not_supported_TICK(this->INTEN);
817 nhw_rtc_eval_interrupts(rtc);
818 }
819 }
820
nhw_rtc_regw_sideeffect_INTENCLR(uint rtc)821 void nhw_rtc_regw_sideeffect_INTENCLR(uint rtc)
822 {
823 struct rtc_status *this = &nhw_rtc_st[rtc];
824 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[rtc];
825
826 if ( RTC_regs->INTENCLR ){
827 this->INTEN &= ~RTC_regs->INTENCLR;
828 RTC_regs->INTENSET = this->INTEN;
829 RTC_regs->INTENCLR = 0;
830
831 nhw_rtc_eval_interrupts(rtc);
832 }
833 }
834
nhw_rtc_regw_sideeffect_EVTENSET(uint i)835 void nhw_rtc_regw_sideeffect_EVTENSET(uint i) {
836 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
837
838 if ( RTC_regs->EVTENSET ){
839 RTC_regs->EVTEN |= RTC_regs->EVTENSET;
840 RTC_regs->EVTENSET = RTC_regs->EVTEN;
841 check_not_supported_TICK(RTC_regs->EVTEN);
842 }
843 }
844
nhw_rtc_regw_sideeffect_EVTENCLR(uint i)845 void nhw_rtc_regw_sideeffect_EVTENCLR(uint i) {
846 NRF_RTC_Type *RTC_regs = &NRF_RTC_regs[i];
847
848 if ( RTC_regs->EVTENCLR ){
849 RTC_regs->EVTEN &= ~RTC_regs->EVTENCLR;
850 RTC_regs->EVTENSET = RTC_regs->EVTEN;
851 RTC_regs->EVTENCLR = 0;
852 }
853 }
854
nhw_rtc_regw_sideeffects_EVENTS_all(uint rtc)855 void nhw_rtc_regw_sideeffects_EVENTS_all(uint rtc) {
856 nhw_rtc_eval_interrupts(rtc);
857 }
858
nhw_rtc_regw_sideeffects_CC(uint rtc,uint cc_n)859 void nhw_rtc_regw_sideeffects_CC(uint rtc, uint cc_n) {
860 struct rtc_status *this = &nhw_rtc_st[rtc];
861
862 if (this->running == true) {
863 update_cc_timer(rtc, cc_n);
864 nhw_rtc_update_master_timer();
865 }
866 }
867
868 #if (NHW_HAS_PPI)
nhw_rtc0_TASKS_START(void)869 void nhw_rtc0_TASKS_START(void) { nhw_rtc_TASKS_START(0); }
nhw_rtc0_TASKS_STOP(void)870 void nhw_rtc0_TASKS_STOP(void) { nhw_rtc_TASKS_STOP(0); }
nhw_rtc0_TASKS_CLEAR(void)871 void nhw_rtc0_TASKS_CLEAR(void) { nhw_rtc_TASKS_CLEAR(0); }
nhw_rtc0_TASKS_TRIGOVRFLW(void)872 void nhw_rtc0_TASKS_TRIGOVRFLW(void) { nhw_rtc_TASKS_TRIGOVRFLW(0); }
nhw_rtc1_TASKS_START(void)873 void nhw_rtc1_TASKS_START(void) { nhw_rtc_TASKS_START(1); }
nhw_rtc1_TASKS_STOP(void)874 void nhw_rtc1_TASKS_STOP(void) { nhw_rtc_TASKS_STOP(1); }
nhw_rtc1_TASKS_CLEAR(void)875 void nhw_rtc1_TASKS_CLEAR(void) { nhw_rtc_TASKS_CLEAR(1); }
nhw_rtc1_TASKS_TRIGOVRFLW(void)876 void nhw_rtc1_TASKS_TRIGOVRFLW(void) { nhw_rtc_TASKS_TRIGOVRFLW(1); }
nhw_rtc2_TASKS_START(void)877 void nhw_rtc2_TASKS_START(void) { nhw_rtc_TASKS_START(2); }
nhw_rtc2_TASKS_STOP(void)878 void nhw_rtc2_TASKS_STOP(void) { nhw_rtc_TASKS_STOP(2); }
nhw_rtc2_TASKS_CLEAR(void)879 void nhw_rtc2_TASKS_CLEAR(void) { nhw_rtc_TASKS_CLEAR(2); }
nhw_rtc2_TASKS_TRIGOVRFLW(void)880 void nhw_rtc2_TASKS_TRIGOVRFLW(void) { nhw_rtc_TASKS_TRIGOVRFLW(2); }
881 #endif /* NHW_HAS_PPI */
882