xref: /nrf52832-nimble/packages/NimBLE-latest/porting/nimble/src/hal_timer.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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