1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <string.h>
21 #include <stdint.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include "os/os.h"
25 #include "nrfx.h"
26 #include "hal/hal_timer.h"
27
28 #define __HAL_DISABLE_INTERRUPTS(x) \
29 do { \
30 x = __get_PRIMASK(); \
31 __disable_irq(); \
32 } while(0);
33
34 #define __HAL_ENABLE_INTERRUPTS(x) \
35 do { \
36 if (!x) { \
37 __enable_irq(); \
38 } \
39 } while(0);
40
41 /* IRQ prototype */
42 typedef void (*hal_timer_irq_handler_t)(void);
43
44 /* User CC 2 for reading counter, CC 3 for timer isr */
45 #define NRF_TIMER_CC_READ (2)
46 #define NRF_TIMER_CC_INT (3)
47
48 /* Output compare 2 used for RTC timers */
49 #define NRF_RTC_TIMER_CC_INT (2)
50
51 /* Maximum number of hal timers used */
52 #define NRF52_HAL_TIMER_MAX (6)
53
54 /* Maximum timer frequency */
55 #define NRF52_MAX_TIMER_FREQ (16000000)
56
57 struct nrf52_hal_timer {
58 uint8_t tmr_enabled;
59 uint8_t tmr_irq_num;
60 uint8_t tmr_rtc;
61 uint8_t tmr_pad;
62 uint32_t tmr_cntr;
63 uint32_t timer_isrs;
64 uint32_t tmr_freq;
65 void *tmr_reg;
66 TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q;
67 };
68
69 #if MYNEWT_VAL(TIMER_0)
70 struct nrf52_hal_timer nrf52_hal_timer0;
71 #endif
72 #if MYNEWT_VAL(TIMER_1)
73 struct nrf52_hal_timer nrf52_hal_timer1;
74 #endif
75 #if MYNEWT_VAL(TIMER_2)
76 struct nrf52_hal_timer nrf52_hal_timer2;
77 #endif
78 #if MYNEWT_VAL(TIMER_3)
79 struct nrf52_hal_timer nrf52_hal_timer3;
80 #endif
81 #if MYNEWT_VAL(TIMER_4)
82 struct nrf52_hal_timer nrf52_hal_timer4;
83 #endif
84 #if MYNEWT_VAL(TIMER_5)
85 struct nrf52_hal_timer nrf52_hal_timer5;
86 #endif
87
88 static const struct nrf52_hal_timer *nrf52_hal_timers[NRF52_HAL_TIMER_MAX] = {
89 #if MYNEWT_VAL(TIMER_0)
90 &nrf52_hal_timer0,
91 #else
92 NULL,
93 #endif
94 #if MYNEWT_VAL(TIMER_1)
95 &nrf52_hal_timer1,
96 #else
97 NULL,
98 #endif
99 #if MYNEWT_VAL(TIMER_2)
100 &nrf52_hal_timer2,
101 #else
102 NULL,
103 #endif
104 #if MYNEWT_VAL(TIMER_3)
105 &nrf52_hal_timer3,
106 #else
107 NULL,
108 #endif
109 #if MYNEWT_VAL(TIMER_4)
110 &nrf52_hal_timer4,
111 #else
112 NULL,
113 #endif
114 #if MYNEWT_VAL(TIMER_5)
115 &nrf52_hal_timer5
116 #else
117 NULL
118 #endif
119 };
120
121 /* Resolve timer number into timer structure */
122 #define NRF52_HAL_TIMER_RESOLVE(__n, __v) \
123 if ((__n) >= NRF52_HAL_TIMER_MAX) { \
124 rc = EINVAL; \
125 goto err; \
126 } \
127 (__v) = (struct nrf52_hal_timer *) nrf52_hal_timers[(__n)]; \
128 if ((__v) == NULL) { \
129 rc = EINVAL; \
130 goto err; \
131 }
132
133 /* Interrupt mask for interrupt enable/clear */
134 #define NRF_TIMER_INT_MASK(x) ((1 << (uint32_t)(x)) << 16)
135
136 static uint32_t
nrf_read_timer_cntr(NRF_TIMER_Type * hwtimer)137 nrf_read_timer_cntr(NRF_TIMER_Type *hwtimer)
138 {
139 uint32_t tcntr;
140
141 /* Force a capture of the timer into 'cntr' capture channel; read it */
142 hwtimer->TASKS_CAPTURE[NRF_TIMER_CC_READ] = 1;
143 tcntr = hwtimer->CC[NRF_TIMER_CC_READ];
144
145 return tcntr;
146 }
147
148 /**
149 * nrf timer set ocmp
150 *
151 * Set the OCMP used by the timer to the desired expiration tick
152 *
153 * NOTE: Must be called with interrupts disabled.
154 *
155 * @param timer Pointer to timer.
156 */
157 static void
nrf_timer_set_ocmp(struct nrf52_hal_timer * bsptimer,uint32_t expiry)158 nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry)
159 {
160 int32_t delta_t;
161 uint32_t temp;
162 uint32_t cntr;
163 NRF_TIMER_Type *hwtimer;
164 NRF_RTC_Type *rtctimer;
165
166 if (bsptimer->tmr_rtc) {
167 rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
168 rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
169 temp = bsptimer->tmr_cntr;
170 cntr = rtctimer->COUNTER;
171 if (rtctimer->EVENTS_OVRFLW) {
172 temp += (1UL << 24);
173 cntr = rtctimer->COUNTER;
174 }
175 temp |= cntr;
176 delta_t = (int32_t)(expiry - temp);
177
178 /*
179 * The nrf documentation states that you must set the output
180 * compare to 2 greater than the counter to guarantee an interrupt.
181 * Since the counter can tick once while we check, we make sure
182 * it is greater than 2.
183 */
184 if (delta_t < 3) {
185 NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
186 } else {
187 if (delta_t < (1UL << 24)) {
188 rtctimer->CC[NRF_RTC_TIMER_CC_INT] = expiry & 0x00ffffff;
189 } else {
190 /* CC too far ahead. Just make sure we set compare far ahead */
191 rtctimer->CC[NRF_RTC_TIMER_CC_INT] = cntr + (1UL << 23);
192 }
193 rtctimer->INTENSET = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
194 }
195 } else {
196 hwtimer = bsptimer->tmr_reg;
197
198 /* Disable ocmp interrupt and set new value */
199 hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
200
201 /* Set output compare register to timer expiration */
202 hwtimer->CC[NRF_TIMER_CC_INT] = expiry;
203
204 /* Clear interrupt flag */
205 hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0;
206
207 /* Enable the output compare interrupt */
208 hwtimer->INTENSET = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
209
210 /* Force interrupt to occur as we may have missed it */
211 if ((int32_t)(nrf_read_timer_cntr(hwtimer) - expiry) >= 0) {
212 NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
213 }
214 }
215 }
216
217 /* Disable output compare used for timer */
218 static void
nrf_timer_disable_ocmp(NRF_TIMER_Type * hwtimer)219 nrf_timer_disable_ocmp(NRF_TIMER_Type *hwtimer)
220 {
221 hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
222 }
223
224 static void
nrf_rtc_disable_ocmp(NRF_RTC_Type * rtctimer)225 nrf_rtc_disable_ocmp(NRF_RTC_Type *rtctimer)
226 {
227 rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
228 }
229
230 static uint32_t
hal_timer_read_bsptimer(struct nrf52_hal_timer * bsptimer)231 hal_timer_read_bsptimer(struct nrf52_hal_timer *bsptimer)
232 {
233 uint32_t low32;
234 uint32_t ctx;
235 uint32_t tcntr;
236 NRF_RTC_Type *rtctimer;
237
238 rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
239 __HAL_DISABLE_INTERRUPTS(ctx);
240 tcntr = bsptimer->tmr_cntr;
241 low32 = rtctimer->COUNTER;
242 if (rtctimer->EVENTS_OVRFLW) {
243 tcntr += (1UL << 24);
244 bsptimer->tmr_cntr = tcntr;
245 low32 = rtctimer->COUNTER;
246 rtctimer->EVENTS_OVRFLW = 0;
247 NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
248 }
249 tcntr |= low32;
250 __HAL_ENABLE_INTERRUPTS(ctx);
251
252 return tcntr;
253 }
254
255 #if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \
256 MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4) || MYNEWT_VAL(TIMER_5))
257 /**
258 * hal timer chk queue
259 *
260 *
261 * @param bsptimer
262 */
263 static void
hal_timer_chk_queue(struct nrf52_hal_timer * bsptimer)264 hal_timer_chk_queue(struct nrf52_hal_timer *bsptimer)
265 {
266 int32_t delta;
267 uint32_t tcntr;
268 uint32_t ctx;
269 struct hal_timer *timer;
270
271 /* disable interrupts */
272 __HAL_DISABLE_INTERRUPTS(ctx);
273 while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) {
274 if (bsptimer->tmr_rtc) {
275 tcntr = hal_timer_read_bsptimer(bsptimer);
276 /*
277 * If we are within 3 ticks of RTC, we wont be able to set compare.
278 * Thus, we have to service this timer early.
279 */
280 delta = -3;
281 } else {
282 tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg);
283 delta = 0;
284 }
285 if ((int32_t)(tcntr - timer->expiry) >= delta) {
286 TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link);
287 timer->link.tqe_prev = NULL;
288 timer->cb_func(timer->cb_arg);
289 } else {
290 break;
291 }
292 }
293
294 /* Any timers left on queue? If so, we need to set OCMP */
295 timer = TAILQ_FIRST(&bsptimer->hal_timer_q);
296 if (timer) {
297 nrf_timer_set_ocmp(bsptimer, timer->expiry);
298 } else {
299 if (bsptimer->tmr_rtc) {
300 nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg);
301 } else {
302 nrf_timer_disable_ocmp(bsptimer->tmr_reg);
303 }
304 }
305 __HAL_ENABLE_INTERRUPTS(ctx);
306 }
307 #endif
308
309 /**
310 * hal timer irq handler
311 *
312 * Generic HAL timer irq handler.
313 *
314 * @param tmr
315 */
316 /**
317 * hal timer irq handler
318 *
319 * This is the global timer interrupt routine.
320 *
321 */
322 #if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \
323 MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4))
324
325 static void
hal_timer_irq_handler(struct nrf52_hal_timer * bsptimer)326 hal_timer_irq_handler(struct nrf52_hal_timer *bsptimer)
327 {
328 uint32_t compare;
329 NRF_TIMER_Type *hwtimer;
330
331 os_trace_enter_isr();
332
333 /* Check interrupt source. If set, clear them */
334 hwtimer = bsptimer->tmr_reg;
335 compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT];
336 if (compare) {
337 hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0;
338 }
339
340 /* XXX: make these stats? */
341 /* Count # of timer isrs */
342 ++bsptimer->timer_isrs;
343
344 /*
345 * NOTE: we dont check the 'compare' variable here due to how the timer
346 * is implemented on this chip. There is no way to force an output
347 * compare, so if we are late setting the output compare (i.e. the timer
348 * counter is already passed the output compare value), we use the NVIC
349 * to set a pending interrupt. This means that there will be no compare
350 * flag set, so all we do is check to see if the compare interrupt is
351 * enabled.
352 */
353 if (hwtimer->INTENCLR & NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)) {
354 hal_timer_chk_queue(bsptimer);
355 /* XXX: Recommended by nordic to make sure interrupts are cleared */
356 compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT];
357 }
358
359 os_trace_exit_isr();
360 }
361 #endif
362
363 #if MYNEWT_VAL(TIMER_5)
364 static void
hal_rtc_timer_irq_handler(struct nrf52_hal_timer * bsptimer)365 hal_rtc_timer_irq_handler(struct nrf52_hal_timer *bsptimer)
366 {
367 uint32_t overflow;
368 uint32_t compare;
369 NRF_RTC_Type *rtctimer;
370
371 /* Check interrupt source. If set, clear them */
372 rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
373 compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT];
374 if (compare) {
375 rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT] = 0;
376 }
377
378 overflow = rtctimer->EVENTS_OVRFLW;
379 if (overflow) {
380 rtctimer->EVENTS_OVRFLW = 0;
381 bsptimer->tmr_cntr += (1UL << 24);
382 }
383
384 /* Count # of timer isrs */
385 ++bsptimer->timer_isrs;
386
387 /*
388 * NOTE: we dont check the 'compare' variable here due to how the timer
389 * is implemented on this chip. There is no way to force an output
390 * compare, so if we are late setting the output compare (i.e. the timer
391 * counter is already passed the output compare value), we use the NVIC
392 * to set a pending interrupt. This means that there will be no compare
393 * flag set, so all we do is check to see if the compare interrupt is
394 * enabled.
395 */
396 hal_timer_chk_queue(bsptimer);
397
398 /* Recommended by nordic to make sure interrupts are cleared */
399 compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT];
400 }
401 #endif
402
403 #if MYNEWT_VAL(TIMER_0)
404 void
nrf52_timer0_irq_handler(void)405 nrf52_timer0_irq_handler(void)
406 {
407 hal_timer_irq_handler(&nrf52_hal_timer0);
408 }
409 #endif
410
411 #if MYNEWT_VAL(TIMER_1)
412 void
nrf52_timer1_irq_handler(void)413 nrf52_timer1_irq_handler(void)
414 {
415 hal_timer_irq_handler(&nrf52_hal_timer1);
416 }
417 #endif
418
419 #if MYNEWT_VAL(TIMER_2)
420 void
nrf52_timer2_irq_handler(void)421 nrf52_timer2_irq_handler(void)
422 {
423 hal_timer_irq_handler(&nrf52_hal_timer2);
424 }
425 #endif
426
427 #if MYNEWT_VAL(TIMER_3)
428 void
nrf52_timer3_irq_handler(void)429 nrf52_timer3_irq_handler(void)
430 {
431 hal_timer_irq_handler(&nrf52_hal_timer3);
432 }
433 #endif
434
435 #if MYNEWT_VAL(TIMER_4)
436 void
nrf52_timer4_irq_handler(void)437 nrf52_timer4_irq_handler(void)
438 {
439 hal_timer_irq_handler(&nrf52_hal_timer4);
440 }
441 #endif
442
443 #if MYNEWT_VAL(TIMER_5)
444 void
nrf52_timer5_irq_handler(void)445 nrf52_timer5_irq_handler(void)
446 {
447 hal_rtc_timer_irq_handler(&nrf52_hal_timer5);
448 }
449 #endif
450
451 /**
452 * hal timer init
453 *
454 * Initialize platform specific timer items
455 *
456 * @param timer_num Timer number to initialize
457 * @param cfg Pointer to platform specific configuration
458 *
459 * @return int 0: success; error code otherwise
460 */
461 int
hal_timer_init(int timer_num,void * cfg)462 hal_timer_init(int timer_num, void *cfg)
463 {
464 int rc;
465 uint8_t irq_num;
466 struct nrf52_hal_timer *bsptimer;
467 void *hwtimer;
468 hal_timer_irq_handler_t irq_isr;
469
470 NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
471
472 /* If timer is enabled do not allow init */
473 if (bsptimer->tmr_enabled) {
474 rc = EINVAL;
475 goto err;
476 }
477
478 switch (timer_num) {
479 #if MYNEWT_VAL(TIMER_5)
480 case 5:
481 irq_num = RTC0_IRQn;
482 hwtimer = NRF_RTC0;
483 irq_isr = nrf52_timer5_irq_handler;
484 bsptimer->tmr_rtc = 1;
485 break;
486 #endif
487 default:
488 hwtimer = NULL;
489 break;
490 }
491
492 if (hwtimer == NULL) {
493 rc = EINVAL;
494 goto err;
495 }
496
497 bsptimer->tmr_reg = hwtimer;
498 bsptimer->tmr_irq_num = irq_num;
499
500 /* Disable IRQ, set priority and set vector in table */
501 NVIC_DisableIRQ(irq_num);
502 #ifndef RIOT_VERSION
503 NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1);
504 #endif
505 #if MYNEWT
506 NVIC_SetVector(irq_num, (uint32_t)irq_isr);
507 #else
508 ble_npl_hw_set_isr(irq_num, irq_isr);
509 #endif
510
511 return 0;
512
513 err:
514 return rc;
515 }
516
517 /**
518 * hal timer config
519 *
520 * Configure a timer to run at the desired frequency. This starts the timer.
521 *
522 * @param timer_num
523 * @param freq_hz
524 *
525 * @return int
526 */
527 int
hal_timer_config(int timer_num,uint32_t freq_hz)528 hal_timer_config(int timer_num, uint32_t freq_hz)
529 {
530 int rc;
531 uint32_t ctx;
532 struct nrf52_hal_timer *bsptimer;
533 #if MYNEWT_VAL(TIMER_5)
534 NRF_RTC_Type *rtctimer;
535 #endif
536
537 NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
538
539 #if MYNEWT_VAL(TIMER_5)
540 if (timer_num == 5) {
541 /* NOTE: we only allow the RTC frequency to be set at 32768 */
542 if (bsptimer->tmr_enabled || (freq_hz != 32768) ||
543 (bsptimer->tmr_reg == NULL)) {
544 rc = EINVAL;
545 goto err;
546 }
547
548 bsptimer->tmr_freq = freq_hz;
549 bsptimer->tmr_enabled = 1;
550
551 __HAL_DISABLE_INTERRUPTS(ctx);
552
553 rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
554
555 /* Stop the timer first */
556 rtctimer->TASKS_STOP = 1;
557
558 /* Always no prescaler */
559 rtctimer->PRESCALER = 0;
560
561 /* Clear overflow events and set overflow interrupt */
562 rtctimer->EVENTS_OVRFLW = 0;
563 rtctimer->INTENSET = RTC_INTENSET_OVRFLW_Msk;
564
565 /* Start the timer */
566 rtctimer->TASKS_START = 1;
567
568 /* Set isr in vector table and enable interrupt */
569 NVIC_EnableIRQ(bsptimer->tmr_irq_num);
570
571 __HAL_ENABLE_INTERRUPTS(ctx);
572 return 0;
573 }
574 #endif
575
576 assert(0);
577
578 return 0;
579
580 err:
581 return rc;
582 }
583
584 /**
585 * hal timer deinit
586 *
587 * De-initialize a HW timer.
588 *
589 * @param timer_num
590 *
591 * @return int
592 */
593 int
hal_timer_deinit(int timer_num)594 hal_timer_deinit(int timer_num)
595 {
596 int rc;
597 uint32_t ctx;
598 struct nrf52_hal_timer *bsptimer;
599 NRF_TIMER_Type *hwtimer;
600 NRF_RTC_Type *rtctimer;
601
602 rc = 0;
603 NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
604
605 __HAL_DISABLE_INTERRUPTS(ctx);
606 if (bsptimer->tmr_rtc) {
607 rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
608 rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
609 rtctimer->TASKS_STOP = 1;
610 } else {
611 hwtimer = (NRF_TIMER_Type *)bsptimer->tmr_reg;
612 hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
613 hwtimer->TASKS_STOP = 1;
614 }
615 bsptimer->tmr_enabled = 0;
616 bsptimer->tmr_reg = NULL;
617 __HAL_ENABLE_INTERRUPTS(ctx);
618
619 err:
620 return rc;
621 }
622
623 /**
624 * hal timer get resolution
625 *
626 * Get the resolution of the timer. This is the timer period, in nanoseconds
627 *
628 * @param timer_num
629 *
630 * @return uint32_t The
631 */
632 uint32_t
hal_timer_get_resolution(int timer_num)633 hal_timer_get_resolution(int timer_num)
634 {
635 int rc;
636 uint32_t resolution;
637 struct nrf52_hal_timer *bsptimer;
638
639 NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
640
641 resolution = 1000000000 / bsptimer->tmr_freq;
642 return resolution;
643
644 err:
645 rc = 0;
646 return rc;
647 }
648
649 /**
650 * hal timer read
651 *
652 * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only
653 * the lower 16 bits are valid. If the timer is a 64-bit timer, only the
654 * low 32-bits are returned.
655 *
656 * @return uint32_t The timer counter register.
657 */
658 uint32_t
hal_timer_read(int timer_num)659 hal_timer_read(int timer_num)
660 {
661 int rc;
662 uint32_t tcntr;
663 struct nrf52_hal_timer *bsptimer;
664
665 NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
666 if (bsptimer->tmr_rtc) {
667 tcntr = hal_timer_read_bsptimer(bsptimer);
668 } else {
669 tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg);
670 }
671
672 return tcntr;
673
674 /* Assert here since there is no invalid return code */
675 err:
676 assert(0);
677 rc = 0;
678 return rc;
679 }
680
681 /**
682 * hal timer delay
683 *
684 * Blocking delay for n ticks
685 *
686 * @param timer_num
687 * @param ticks
688 *
689 * @return int 0 on success; error code otherwise.
690 */
691 int
hal_timer_delay(int timer_num,uint32_t ticks)692 hal_timer_delay(int timer_num, uint32_t ticks)
693 {
694 uint32_t until;
695
696 until = hal_timer_read(timer_num) + ticks;
697 while ((int32_t)(hal_timer_read(timer_num) - until) <= 0) {
698 /* Loop here till finished */
699 }
700
701 return 0;
702 }
703
704 /**
705 *
706 * Initialize the HAL timer structure with the callback and the callback
707 * argument. Also initializes the HW specific timer pointer.
708 *
709 * @param cb_func
710 *
711 * @return int
712 */
713 int
hal_timer_set_cb(int timer_num,struct hal_timer * timer,hal_timer_cb cb_func,void * arg)714 hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func,
715 void *arg)
716 {
717 int rc;
718 struct nrf52_hal_timer *bsptimer;
719
720 NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
721
722 timer->cb_func = cb_func;
723 timer->cb_arg = arg;
724 timer->link.tqe_prev = NULL;
725 timer->bsp_timer = bsptimer;
726
727 rc = 0;
728
729 err:
730 return rc;
731 }
732
733 int
hal_timer_start(struct hal_timer * timer,uint32_t ticks)734 hal_timer_start(struct hal_timer *timer, uint32_t ticks)
735 {
736 int rc;
737 uint32_t tick;
738 struct nrf52_hal_timer *bsptimer;
739
740 /* Set the tick value at which the timer should expire */
741 bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
742 if (bsptimer->tmr_rtc) {
743 tick = hal_timer_read_bsptimer(bsptimer) + ticks;
744 } else {
745 tick = nrf_read_timer_cntr(bsptimer->tmr_reg) + ticks;
746 }
747 rc = hal_timer_start_at(timer, tick);
748 return rc;
749 }
750
751 int
hal_timer_start_at(struct hal_timer * timer,uint32_t tick)752 hal_timer_start_at(struct hal_timer *timer, uint32_t tick)
753 {
754 uint32_t ctx;
755 struct hal_timer *entry;
756 struct nrf52_hal_timer *bsptimer;
757
758 if ((timer == NULL) || (timer->link.tqe_prev != NULL) ||
759 (timer->cb_func == NULL)) {
760 return EINVAL;
761 }
762 bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
763 timer->expiry = tick;
764
765 __HAL_DISABLE_INTERRUPTS(ctx);
766
767 if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) {
768 TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link);
769 } else {
770 TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) {
771 if ((int32_t)(timer->expiry - entry->expiry) < 0) {
772 TAILQ_INSERT_BEFORE(entry, timer, link);
773 break;
774 }
775 }
776 if (!entry) {
777 TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link);
778 }
779 }
780
781 /* If this is the head, we need to set new OCMP */
782 if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) {
783 nrf_timer_set_ocmp(bsptimer, timer->expiry);
784 }
785
786 __HAL_ENABLE_INTERRUPTS(ctx);
787
788 return 0;
789 }
790
791 /**
792 * hal timer stop
793 *
794 * Stop a timer.
795 *
796 * @param timer
797 *
798 * @return int
799 */
800 int
hal_timer_stop(struct hal_timer * timer)801 hal_timer_stop(struct hal_timer *timer)
802 {
803 uint32_t ctx;
804 int reset_ocmp;
805 struct hal_timer *entry;
806 struct nrf52_hal_timer *bsptimer;
807
808 if (timer == NULL) {
809 return EINVAL;
810 }
811
812 bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
813
814 __HAL_DISABLE_INTERRUPTS(ctx);
815
816 if (timer->link.tqe_prev != NULL) {
817 reset_ocmp = 0;
818 if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) {
819 /* If first on queue, we will need to reset OCMP */
820 entry = TAILQ_NEXT(timer, link);
821 reset_ocmp = 1;
822 }
823 TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link);
824 timer->link.tqe_prev = NULL;
825 if (reset_ocmp) {
826 if (entry) {
827 nrf_timer_set_ocmp((struct nrf52_hal_timer *)entry->bsp_timer,
828 entry->expiry);
829 } else {
830 if (bsptimer->tmr_rtc) {
831 nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg);
832 } else {
833 nrf_timer_disable_ocmp(bsptimer->tmr_reg);
834 }
835 }
836 }
837 }
838
839 __HAL_ENABLE_INTERRUPTS(ctx);
840
841 return 0;
842 }
843