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 * TIMER - Timer/counter
9 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/timer.html?cp=5_1_0_5_27
10 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/timer.html?cp=4_0_0_6_34
11 */
12
13 /**
14 * Notes:
15 * * The functionality of TASK_SHUTDOWN is a bit of a guess
16 * * INTENCLR will always read as 0
17 * * Unlike in real HW, tasks cannot occur simultaneously, they always happen in some sequence
18 * so task priority is not accounted for
19 *
20 * Implementation notes:
21 *
22 * In Timer mode, the timer is not actually counting all the time, but instead
23 * a HW event timer is programmed on the expected matches' times whenever the
24 * timer is started, stopped, or the compare values are updated.
25 *
26 * In Count mode, the timer count value (Counter[t]) is updated each time the
27 * corresponding TASK_COUNT is triggered.
28 */
29
30 #include <string.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include "NHW_common_types.h"
34 #include "NHW_config.h"
35 #include "NHW_peri_types.h"
36 #include "NHW_TIMER.h"
37 #include "nsi_hw_scheduler.h"
38 #include "NHW_xPPI.h"
39 #include "irq_ctrl.h"
40 #include "bs_tracing.h"
41 #include "bs_oswrap.h"
42 #include "nsi_tasks.h"
43 #include "nsi_hws_models_if.h"
44
45 #define N_TIMERS NHW_TIMER_TOTAL_INST
46 #define N_MAX_CC NHW_TIMER_MAX_N_CC
47
48 struct timer_status {
49 NRF_TIMER_Type *NRF_TIMER_regs;
50
51 int n_CCs; //Number of compare/capture registers in this timer instance
52 int base_freq; //Base frequency (in MHz) of the timer input clock
53
54 bs_time_t *CC_timers; //[n_CCs] In timer mode: When each compare match is expected to happen
55 bool *oneshot_flag; //[n_CCs] The CC register has been written, and a compare event has not yet been generated
56 bs_time_t start_t; //Time when the timer was started (only for timer mode)
57 uint32_t Counter; //Internal count value. Used in count mode, and in Timer mode during stops.
58 uint32_t INTEN;
59 bool is_running;
60
61 #if (NHW_HAS_DPPI)
62 uint dppi_map; //To which DPPI instance are this TIMER subscribe&publish ports connected to
63 //Which of the subscription ports are currently connected, and to which channel:
64 struct nhw_subsc_mem* subscribed_CAPTURE; //[n_CCs]
65 struct nhw_subsc_mem subscribed_START;
66 struct nhw_subsc_mem subscribed_STOP;
67 struct nhw_subsc_mem subscribed_COUNT;
68 struct nhw_subsc_mem subscribed_CLEAR;
69 struct nhw_subsc_mem subscribed_SHUTDOWN;
70 #endif
71 };
72
73 static bs_time_t Timer_TIMERs = TIME_NEVER;
74 static struct timer_status nhw_timer_st[NHW_TIMER_TOTAL_INST];
75 NRF_TIMER_Type NRF_TIMER_regs[NHW_TIMER_TOTAL_INST];
76
77 /**
78 * Initialize the TIMER model
79 */
nhw_timer_init(void)80 static void nhw_timer_init(void) {
81 #if (NHW_HAS_DPPI)
82 /* Mapping of peripheral instance to DPPI instance */
83 uint nhw_timer_dppi_map[NHW_TIMER_TOTAL_INST] = NHW_TIMER_DPPI_MAP;
84 #endif
85 int Timer_n_CCs[N_TIMERS] = NHW_TIMER_N_CC;
86 int Timer_freqs[N_TIMERS] = NHW_TIMER_FREQ;
87
88 memset(NRF_TIMER_regs, 0, sizeof(NRF_TIMER_regs));
89
90 for (int t = 0; t < NHW_TIMER_TOTAL_INST ; t++) {
91 struct timer_status *t_st = &nhw_timer_st[t];
92
93 t_st->NRF_TIMER_regs = &NRF_TIMER_regs[t];
94
95 t_st->INTEN = 0;
96 t_st->is_running = false;
97 t_st->start_t = TIME_NEVER;
98 t_st->Counter = 0;
99
100 t_st->base_freq = Timer_freqs[t];
101 t_st->n_CCs = Timer_n_CCs[t];
102 t_st->CC_timers = (bs_time_t *)bs_malloc(sizeof(bs_time_t)*Timer_n_CCs[t]);
103 t_st->oneshot_flag = (bool *)bs_calloc(Timer_n_CCs[t], sizeof(bool));
104
105 for (int cc = 0; cc < t_st->n_CCs ; cc++) {
106 t_st->CC_timers[cc] = TIME_NEVER;
107 }
108
109 #if (NHW_HAS_DPPI)
110 t_st->dppi_map = nhw_timer_dppi_map[t];
111 t_st->subscribed_CAPTURE = (struct nhw_subsc_mem*)bs_calloc(Timer_n_CCs[t], sizeof(struct nhw_subsc_mem));
112 #endif
113 }
114 Timer_TIMERs = TIME_NEVER;
115 }
116
117 NSI_TASK(nhw_timer_init, HW_INIT, 100);
118
119 /*
120 * Free all TIMER instances resources before program exit
121 */
nhw_timer_free(void)122 static void nhw_timer_free(void)
123 {
124 for (int t = 0; t< NHW_TIMER_TOTAL_INST; t++) {
125 struct timer_status *t_st = &nhw_timer_st[t];
126
127 free(t_st->CC_timers);
128 t_st->CC_timers = NULL;
129
130 free(t_st->oneshot_flag);
131 t_st->oneshot_flag = NULL;
132
133 #if (NHW_HAS_DPPI)
134 free(t_st->subscribed_CAPTURE);
135 t_st->subscribed_CAPTURE = NULL;
136 #endif /* (NHW_HAS_DPPI) */
137 }
138 }
139
140 NSI_TASK(nhw_timer_free, ON_EXIT_PRE, 100);
141
142 /**
143 * Convert a time delta in us to the equivalent count accounting for the PRESCALER
144 * The timer base clock is 16MHz
145 */
time_to_counter(bs_time_t delta,int t)146 static uint32_t time_to_counter(bs_time_t delta, int t){
147 uint64_t ticks;
148 ticks = ( delta << 4 ) >> NRF_TIMER_regs[t].PRESCALER;
149 return ticks;
150 }
151
152 /**
153 * Convert a counter delta to us accounting for the PRESCALER
154 * The timer base clock is 16MHz
155 */
counter_to_time(uint64_t counter,int t)156 static bs_time_t counter_to_time(uint64_t counter, int t){
157 bs_time_t Elapsed;
158 Elapsed = ( counter << NRF_TIMER_regs[t].PRESCALER ) >> 4;
159 return Elapsed;
160 }
161
162 /**
163 * Return the counter mask (due to BITMODE) for this TIMER<t>
164 */
mask_from_bitmode(int t)165 static uint32_t mask_from_bitmode(int t){
166 switch (NRF_TIMER_regs[t].BITMODE){
167 case 0:
168 return 0xFFFF;
169 break;
170 case 1:
171 return 0xFF;
172 break;
173 case 2:
174 return 0xFFFFFF;
175 break;
176 default:
177 return 0xFFFFFFFF;
178 break;
179 }
180 }
181
182 /**
183 * Return the time in us it takes for the COUNTER to do 1 wrap
184 * given BITMODE
185 */
time_of_1_counter_wrap(int t)186 static uint64_t time_of_1_counter_wrap(int t){
187 return counter_to_time((uint64_t)mask_from_bitmode(t) + 1, t);
188 }
189
190 /**
191 * Find the CC register timer (CC_timers[][]) which will trigger earliest (if any)
192 */
update_master_timer(void)193 static void update_master_timer(void) {
194 Timer_TIMERs = TIME_NEVER;
195
196 for ( int t = 0 ; t < N_TIMERS ; t++){
197 struct timer_status *t_st = &nhw_timer_st[t];
198
199 if ((t_st->is_running == true) && (NRF_TIMER_regs[t].MODE == 0)) {
200 for (int cc = 0 ; cc < t_st->n_CCs ; cc++) {
201 if (t_st->CC_timers[cc] < Timer_TIMERs) {
202 Timer_TIMERs = t_st->CC_timers[cc];
203 }
204 }
205 }
206 }
207 nsi_hws_find_next_event();
208 }
209
210 /**
211 * Save in CC_timers[t][cc] the next time when this timer will match the CC[cc]
212 * register
213 */
update_cc_timer(int t,int cc)214 static void update_cc_timer(int t, int cc) {
215 struct timer_status *this = &nhw_timer_st[t];
216
217 if ((this->is_running == true) && (NRF_TIMER_regs[t].MODE == 0)) {
218 bs_time_t next_match = this->start_t
219 + counter_to_time(NRF_TIMER_regs[t].CC[cc], t);
220 while (next_match <= nsi_hws_get_time()) {
221 next_match += time_of_1_counter_wrap(t);
222 }
223 this->CC_timers[cc] = next_match;
224 } else {
225 this->CC_timers[cc] = TIME_NEVER;
226 }
227 }
228
update_all_cc_timers(int t)229 static void update_all_cc_timers(int t) {
230 for (int cc = 0 ; cc < nhw_timer_st[t].n_CCs; cc++) {
231 update_cc_timer(t, cc);
232 }
233 }
234
nhw_timer_eval_interrupts(int t)235 static void nhw_timer_eval_interrupts(int t) {
236 /* Mapping of peripheral instance to {int controller instance, int number} */
237 static struct nhw_irq_mapping nhw_timer_irq_map[NHW_TIMER_TOTAL_INST] = NHW_TIMER_INT_MAP;
238 static bool TIMER_int_line[N_TIMERS]; /* Is the TIMER currently driving its interrupt line high */
239
240 struct timer_status *this = &nhw_timer_st[t];
241 bool new_int_line = false;
242
243 for (int cc = 0; cc < this->n_CCs; cc++) {
244 int mask = this->INTEN & (TIMER_INTENSET_COMPARE0_Msk << cc);
245 if (NRF_TIMER_regs[t].EVENTS_COMPARE[cc] && mask) {
246 new_int_line = true;
247 break; /* No need to check more */
248 }
249 }
250
251 if (TIMER_int_line[t] == false && new_int_line == true) {
252 TIMER_int_line[t] = true;
253 hw_irq_ctrl_raise_level_irq_line(nhw_timer_irq_map[t].cntl_inst,
254 nhw_timer_irq_map[t].int_nbr);
255 } else if (TIMER_int_line[t] == true && new_int_line == false) {
256 TIMER_int_line[t] = false;
257
258 hw_irq_ctrl_lower_level_irq_line(nhw_timer_irq_map[t].cntl_inst,
259 nhw_timer_irq_map[t].int_nbr);
260 }
261 }
262
nhw_timer_TASK_START(int t)263 void nhw_timer_TASK_START(int t){
264 struct timer_status *this = &nhw_timer_st[t];
265
266 //Note: STATUS is missing in NRF_TIMER_Type
267 if (this->is_running == false) {
268 this->is_running = true;
269 if (NRF_TIMER_regs[t].MODE == 0) { //Timer mode
270 this->start_t = nsi_hws_get_time() - counter_to_time(this->Counter, t); //If the counter is not zero at start, is like if the counter was started earlier
271 update_all_cc_timers(t);
272 update_master_timer();
273 }
274 }
275 }
276
nhw_timer_TASK_STOP(int t)277 void nhw_timer_TASK_STOP(int t) {
278 struct timer_status *this = &nhw_timer_st[t];
279
280 //Note: STATUS is missing in NRF_TIMER_Type
281 if (this->is_running == true) {
282 this->is_running = false;
283 if (NRF_TIMER_regs[t].MODE == 0) { //Timer mode
284 this->Counter = time_to_counter(nsi_hws_get_time() - this->start_t, t); //we save the value when the counter was stoped in case it is started again without clearing it
285 }
286 for (int cc = 0 ; cc < this->n_CCs ; cc++) {
287 this->CC_timers[cc] = TIME_NEVER;
288 }
289 update_master_timer();
290 }
291 }
292
nhw_timer_TASK_SHUTDOWN(int t)293 void nhw_timer_TASK_SHUTDOWN(int t) {
294 struct timer_status *this = &nhw_timer_st[t];
295
296 /*
297 * TASK_SHUTDOWN is not documented in newer SOCs
298 * In older ones it indicates it STOPS + it reduces power consumption
299 * but that it cannot be resumed after from where it was
300 * The assumption is that the internal count is lost/reset to 0
301 * Effectively making a SHUTDOWN logically equivalent to a STOP + CLEAR
302 */
303 //Note: STATUS is missing in NRF_TIMER_Type
304 this->is_running = false;
305 this->Counter = 0;
306 this->start_t = TIME_NEVER;
307 for (int cc = 0 ; cc < this->n_CCs ; cc++){
308 this->CC_timers[cc] = TIME_NEVER;
309 }
310 update_master_timer();
311 }
312
nhw_timer_TASK_CAPTURE(int t,int cc_n)313 void nhw_timer_TASK_CAPTURE(int t, int cc_n) {
314 struct timer_status *this = &nhw_timer_st[t];
315
316 if (cc_n >= this->n_CCs) {
317 bs_trace_error_line_time("%s: Attempted to access non existing task"
318 "TIMER%i.TASK_CAPTURE[%i] (>= %i)\n",
319 t, cc_n, this->n_CCs);
320 }
321 if ( NRF_TIMER_regs[t].MODE != 0 ){ //Count mode
322 NRF_TIMER_regs[t].CC[cc_n] = this->Counter & mask_from_bitmode(t);
323 } else { //Timer mode:
324 if ( this->start_t == TIME_NEVER ){
325 bs_trace_warning_line_time("NRF HW TIMER%i TASK_CAPTURE[%i] "
326 "triggered on a timer which was never "
327 "started => you get garbage\n", t, cc_n);
328 }
329 bs_time_t Elapsed = nsi_hws_get_time() - this->start_t;
330 NRF_TIMER_regs[t].CC[cc_n] = time_to_counter(Elapsed,t) & mask_from_bitmode(t);
331
332 //The new CC causes a new possible CC match time:
333 update_cc_timer(t, cc_n);
334 update_master_timer();
335 }
336 }
337
nhw_timer_TASK_CLEAR(uint t)338 void nhw_timer_TASK_CLEAR(uint t) {
339 struct timer_status *this = &nhw_timer_st[t];
340
341 this->Counter = 0;
342 if (NRF_TIMER_regs[t].MODE == 0) {
343 //Timer mode:
344 this->start_t = nsi_hws_get_time();
345 update_all_cc_timers(t);
346 update_master_timer();
347 }
348 }
349
nhw_timer_signal_COMPARE(uint t,uint cc)350 static void nhw_timer_signal_COMPARE(uint t, uint cc) {
351 struct timer_status *this = &nhw_timer_st[t];
352 NRF_TIMER_Type *TIMER_regs = this->NRF_TIMER_regs;
353
354 if (TIMER_regs->SHORTS & (TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc)) {
355 nhw_timer_TASK_CLEAR(t);
356 }
357 if (TIMER_regs->SHORTS & (TIMER_SHORTS_COMPARE0_STOP_Msk << cc)) {
358 nhw_timer_TASK_STOP(t);
359 }
360
361 TIMER_regs->EVENTS_COMPARE[cc] = 1;
362
363 nhw_timer_eval_interrupts(t);
364
365 #if (NHW_HAS_PPI)
366 ppi_event_types_t event_cc;
367 switch (t) {
368 case 0:
369 event_cc = TIMER0_EVENTS_COMPARE_0;
370 break;
371 case 1:
372 event_cc = TIMER1_EVENTS_COMPARE_0;
373 break;
374 case 2:
375 event_cc = TIMER2_EVENTS_COMPARE_0;
376 break;
377 case 3:
378 event_cc = TIMER3_EVENTS_COMPARE_0;
379 break;
380 case 4:
381 default: /* This default is just to silence a -Werror=maybe-uninitialized warning */
382 event_cc = TIMER4_EVENTS_COMPARE_0;
383 break;
384 }
385 nrf_ppi_event(event_cc + cc);
386 #elif (NHW_HAS_DPPI)
387 nhw_dppi_event_signal_if(this->dppi_map,
388 TIMER_regs->PUBLISH_COMPARE[cc]);
389 #endif
390 }
391
nhw_timer_signal_COMPARE_if(uint t,uint cc_n)392 static void nhw_timer_signal_COMPARE_if(uint t, uint cc_n) {
393 struct timer_status *this = &nhw_timer_st[t];
394 #if (NHW_TIMER_HAS_ONE_SHOT)
395 if ((this->oneshot_flag[cc_n] == false) && this->NRF_TIMER_regs->ONESHOTEN[cc_n]) {
396 return;
397 }
398 #endif
399 this->oneshot_flag[cc_n] = false;
400 nhw_timer_signal_COMPARE(t, cc_n);
401 }
402
nhw_timer_TASK_COUNT(uint t)403 void nhw_timer_TASK_COUNT(uint t) {
404 struct timer_status *this = &nhw_timer_st[t];
405
406 if ((NRF_TIMER_regs[t].MODE != 0 /* Count mode */) && (this->is_running == true)) {
407 this->Counter = (this->Counter + 1) & mask_from_bitmode(t);
408
409 for (int cc_n = 0; cc_n < this->n_CCs; cc_n++) {
410 if (this->Counter == (NRF_TIMER_regs[t].CC[cc_n] & mask_from_bitmode(t))){
411 nhw_timer_signal_COMPARE_if(t, cc_n);
412 }
413 }
414 } //Otherwise ignored
415 }
416
nhw_timer_regw_sideeffects_TASKS_START(uint t)417 void nhw_timer_regw_sideeffects_TASKS_START(uint t) {
418 if ( NRF_TIMER_regs[t].TASKS_START ){
419 NRF_TIMER_regs[t].TASKS_START = 0;
420 nhw_timer_TASK_START(t);
421 }
422 }
423
nhw_timer_regw_sideeffects_TASKS_STOP(uint t)424 void nhw_timer_regw_sideeffects_TASKS_STOP(uint t) {
425 if (NRF_TIMER_regs[t].TASKS_STOP) {
426 NRF_TIMER_regs[t].TASKS_STOP = 0;
427 nhw_timer_TASK_STOP(t);
428 }
429 }
430
nhw_timer_regw_sideeffects_TASKS_SHUTDOWN(uint t)431 void nhw_timer_regw_sideeffects_TASKS_SHUTDOWN(uint t) {
432 if (NRF_TIMER_regs[t].TASKS_SHUTDOWN) {
433 NRF_TIMER_regs[t].TASKS_SHUTDOWN = 0;
434 nhw_timer_TASK_SHUTDOWN(t);
435 }
436 }
437
nhw_timer_regw_sideeffects_TASKS_CAPTURE(uint t,uint cc_n)438 void nhw_timer_regw_sideeffects_TASKS_CAPTURE(uint t, uint cc_n){
439 if ( NRF_TIMER_regs[t].TASKS_CAPTURE[cc_n] ){
440 NRF_TIMER_regs[t].TASKS_CAPTURE[cc_n] = 0;
441 nhw_timer_TASK_CAPTURE(t,cc_n);
442 }
443 }
444
nhw_timer_regw_sideeffects_TASKS_CLEAR(uint t)445 void nhw_timer_regw_sideeffects_TASKS_CLEAR(uint t) {
446 if (NRF_TIMER_regs[t].TASKS_CLEAR) {
447 NRF_TIMER_regs[t].TASKS_CLEAR = 0;
448 nhw_timer_TASK_CLEAR(t);
449 }
450 }
451
nhw_timer_regw_sideeffects_TASKS_COUNT(uint t)452 void nhw_timer_regw_sideeffects_TASKS_COUNT(uint t) {
453 if ( NRF_TIMER_regs[t].TASKS_COUNT ){
454 NRF_TIMER_regs[t].TASKS_COUNT = 0;
455 nhw_timer_TASK_COUNT(t);
456 }
457 }
458
459 #if (NHW_HAS_DPPI)
460
nhw_timer_taskcapture_wrap(void * param)461 static void nhw_timer_taskcapture_wrap(void* param) {
462 unsigned int inst = (uintptr_t)param >> 16;
463 uint cc_n = (uintptr_t)param & 0xFFFF;
464 nhw_timer_TASK_CAPTURE(inst, cc_n);
465 }
466
nhw_timer_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst,uint cc_n)467 void nhw_timer_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst, uint cc_n) {
468 struct timer_status *this = &nhw_timer_st[inst];
469
470 nhw_dppi_common_subscribe_sideeffect(this->dppi_map,
471 this->NRF_TIMER_regs->SUBSCRIBE_CAPTURE[cc_n],
472 &this->subscribed_CAPTURE[cc_n],
473 nhw_timer_taskcapture_wrap,
474 (void*)((inst << 16) + cc_n));
475 }
476
477 #define NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N) \
478 static void nhw_timer_task##TASK_N##_wrap(void* param) \
479 { \
480 nhw_timer_TASK_##TASK_N((int) param); \
481 } \
482 \
483 void nhw_timer_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst) \
484 { \
485 struct timer_status *this = &nhw_timer_st[inst]; \
486 \
487 nhw_dppi_common_subscribe_sideeffect(this->dppi_map, \
488 this->NRF_TIMER_regs->SUBSCRIBE_##TASK_N, \
489 &this->subscribed_##TASK_N, \
490 nhw_timer_task##TASK_N##_wrap, \
491 (void*) inst); \
492 }
493
494 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(START)
NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(STOP)495 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(STOP)
496 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(COUNT)
497 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(CLEAR)
498 NHW_TIMER_REGW_SIDEFFECTS_SUBSCRIBE(SHUTDOWN)
499
500 #endif /* NHW_HAS_DPPI */
501
502
503 void nhw_timer_regw_sideeffects_EVENTS_all(uint t) {
504 nhw_timer_eval_interrupts(t);
505 }
506
nhw_timer_regw_sideeffects_INTENSET(uint t)507 void nhw_timer_regw_sideeffects_INTENSET(uint t) {
508 struct timer_status *this = &nhw_timer_st[t];
509
510 if ( NRF_TIMER_regs[t].INTENSET ){
511 this->INTEN |= NRF_TIMER_regs[t].INTENSET;
512 NRF_TIMER_regs[t].INTENSET = this->INTEN;
513 nhw_timer_eval_interrupts(t);
514 }
515 }
516
nhw_timer_regw_sideeffects_INTENCLR(uint t)517 void nhw_timer_regw_sideeffects_INTENCLR(uint t) {
518 struct timer_status *this = &nhw_timer_st[t];
519
520 if ( NRF_TIMER_regs[t].INTENCLR ){
521 this->INTEN &= ~NRF_TIMER_regs[t].INTENCLR;
522 NRF_TIMER_regs[t].INTENSET = this->INTEN;
523 NRF_TIMER_regs[t].INTENCLR = 0;
524 nhw_timer_eval_interrupts(t);
525 }
526 }
527
nhw_timer_regw_sideeffects_CC(uint t,uint cc_n)528 void nhw_timer_regw_sideeffects_CC(uint t, uint cc_n) {
529 struct timer_status *this = &nhw_timer_st[t];
530
531 if (cc_n >= this->n_CCs) {
532 bs_trace_error_line_time("%s: Attempted to access non existing register "
533 "TIMER%i.CC[%i] (>= %i)\n",
534 __func__, t, cc_n, this->n_CCs);
535 }
536
537 this->oneshot_flag[cc_n] = true;
538
539 if ( (this->is_running == true) && ( NRF_TIMER_regs[t].MODE == 0 ) ) {
540 update_cc_timer(t, cc_n);
541 update_master_timer();
542 }
543 }
544
nhw_hw_model_timer_timer_triggered(void)545 static void nhw_hw_model_timer_timer_triggered(void) {
546 unsigned int t, cc;
547 struct {
548 unsigned int t[N_TIMERS*N_MAX_CC];
549 unsigned int cc[N_TIMERS*N_MAX_CC];
550 unsigned int cnt;
551 } match;
552
553 match.cnt = 0;
554
555 for (t = 0 ; t < N_TIMERS ; t++) {
556 struct timer_status *t_st = &nhw_timer_st[t];
557
558 if ( !((t_st->is_running == true) && (NRF_TIMER_regs[t].MODE == 0)) ) {
559 continue;
560 }
561 for (cc = 0 ; cc < t_st->n_CCs ; cc++) {
562 if (t_st->CC_timers[cc] == Timer_TIMERs) {
563 match.t[match.cnt] = t;
564 match.cc[match.cnt] = cc;
565 match.cnt++;
566 }
567 }
568 }
569 while (match.cnt > 0) {
570 match.cnt--;
571 t = match.t[match.cnt];
572 cc = match.cc[match.cnt];
573 update_cc_timer(t,cc); //Next time it will match
574 nhw_timer_signal_COMPARE_if(t,cc);
575 }
576 update_master_timer();
577 }
578
579 NSI_HW_EVENT(Timer_TIMERs, nhw_hw_model_timer_timer_triggered, 50);
580
581 #if (NHW_HAS_PPI)
nhw_timer0_TASK_START(void)582 void nhw_timer0_TASK_START(void) { nhw_timer_TASK_START(0); }
nhw_timer1_TASK_START(void)583 void nhw_timer1_TASK_START(void) { nhw_timer_TASK_START(1); }
nhw_timer2_TASK_START(void)584 void nhw_timer2_TASK_START(void) { nhw_timer_TASK_START(2); }
nhw_timer3_TASK_START(void)585 void nhw_timer3_TASK_START(void) { nhw_timer_TASK_START(3); }
nhw_timer4_TASK_START(void)586 void nhw_timer4_TASK_START(void) { nhw_timer_TASK_START(4); }
587
nhw_timer0_TASK_STOP(void)588 void nhw_timer0_TASK_STOP(void) { nhw_timer_TASK_STOP(0); }
nhw_timer1_TASK_STOP(void)589 void nhw_timer1_TASK_STOP(void) { nhw_timer_TASK_STOP(1); }
nhw_timer2_TASK_STOP(void)590 void nhw_timer2_TASK_STOP(void) { nhw_timer_TASK_STOP(2); }
nhw_timer3_TASK_STOP(void)591 void nhw_timer3_TASK_STOP(void) { nhw_timer_TASK_STOP(3); }
nhw_timer4_TASK_STOP(void)592 void nhw_timer4_TASK_STOP(void) { nhw_timer_TASK_STOP(4); }
593
nhw_timer0_TASK_CAPTURE_0(void)594 void nhw_timer0_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(0,0); }
nhw_timer0_TASK_CAPTURE_1(void)595 void nhw_timer0_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(0,1); }
nhw_timer0_TASK_CAPTURE_2(void)596 void nhw_timer0_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(0,2); }
nhw_timer0_TASK_CAPTURE_3(void)597 void nhw_timer0_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(0,3); }
598
nhw_timer1_TASK_CAPTURE_0(void)599 void nhw_timer1_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(1,0); }
nhw_timer1_TASK_CAPTURE_1(void)600 void nhw_timer1_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(1,1); }
nhw_timer1_TASK_CAPTURE_2(void)601 void nhw_timer1_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(1,2); }
nhw_timer1_TASK_CAPTURE_3(void)602 void nhw_timer1_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(1,3); }
603
nhw_timer2_TASK_CAPTURE_0(void)604 void nhw_timer2_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(2,0); }
nhw_timer2_TASK_CAPTURE_1(void)605 void nhw_timer2_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(2,1); }
nhw_timer2_TASK_CAPTURE_2(void)606 void nhw_timer2_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(2,2); }
nhw_timer2_TASK_CAPTURE_3(void)607 void nhw_timer2_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(2,3); }
608
nhw_timer3_TASK_CAPTURE_0(void)609 void nhw_timer3_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(3,0); }
nhw_timer3_TASK_CAPTURE_1(void)610 void nhw_timer3_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(3,1); }
nhw_timer3_TASK_CAPTURE_2(void)611 void nhw_timer3_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(3,2); }
nhw_timer3_TASK_CAPTURE_3(void)612 void nhw_timer3_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(3,3); }
nhw_timer3_TASK_CAPTURE_4(void)613 void nhw_timer3_TASK_CAPTURE_4(void) { nhw_timer_TASK_CAPTURE(3,4); }
nhw_timer3_TASK_CAPTURE_5(void)614 void nhw_timer3_TASK_CAPTURE_5(void) { nhw_timer_TASK_CAPTURE(3,5); }
615
nhw_timer4_TASK_CAPTURE_0(void)616 void nhw_timer4_TASK_CAPTURE_0(void) { nhw_timer_TASK_CAPTURE(4,0); }
nhw_timer4_TASK_CAPTURE_1(void)617 void nhw_timer4_TASK_CAPTURE_1(void) { nhw_timer_TASK_CAPTURE(4,1); }
nhw_timer4_TASK_CAPTURE_2(void)618 void nhw_timer4_TASK_CAPTURE_2(void) { nhw_timer_TASK_CAPTURE(4,2); }
nhw_timer4_TASK_CAPTURE_3(void)619 void nhw_timer4_TASK_CAPTURE_3(void) { nhw_timer_TASK_CAPTURE(4,3); }
nhw_timer4_TASK_CAPTURE_4(void)620 void nhw_timer4_TASK_CAPTURE_4(void) { nhw_timer_TASK_CAPTURE(4,4); }
nhw_timer4_TASK_CAPTURE_5(void)621 void nhw_timer4_TASK_CAPTURE_5(void) { nhw_timer_TASK_CAPTURE(4,5); }
622
nhw_timer0_TASK_CLEAR(void)623 void nhw_timer0_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(0); }
nhw_timer1_TASK_CLEAR(void)624 void nhw_timer1_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(1); }
nhw_timer2_TASK_CLEAR(void)625 void nhw_timer2_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(2); }
nhw_timer3_TASK_CLEAR(void)626 void nhw_timer3_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(3); }
nhw_timer4_TASK_CLEAR(void)627 void nhw_timer4_TASK_CLEAR(void) { nhw_timer_TASK_CLEAR(4); }
628
nhw_timer0_TASK_COUNT(void)629 void nhw_timer0_TASK_COUNT(void) { nhw_timer_TASK_COUNT(0); }
nhw_timer1_TASK_COUNT(void)630 void nhw_timer1_TASK_COUNT(void) { nhw_timer_TASK_COUNT(1); }
nhw_timer2_TASK_COUNT(void)631 void nhw_timer2_TASK_COUNT(void) { nhw_timer_TASK_COUNT(2); }
nhw_timer3_TASK_COUNT(void)632 void nhw_timer3_TASK_COUNT(void) { nhw_timer_TASK_COUNT(3); }
nhw_timer4_TASK_COUNT(void)633 void nhw_timer4_TASK_COUNT(void) { nhw_timer_TASK_COUNT(4); }
634 #endif /* (NHW_HAS_PPI) */
635