Contiki 3.x
rtimer-arch.c
1 /**
2  * Copyright (c) 2014, Analog Devices, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted (subject to the limitations in the
6  * disclaimer below) provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the
14  * distribution.
15  *
16  * - Neither the name of Analog Devices, Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
21  * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
22  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 /**
35  * \author Jim Paris <jim.paris@rigado.com>
36  */
37 
38 #include <contiki.h>
39 #include "rtimer-arch.h"
40 #include "aducrf101-contiki.h"
41 
42 /* rtimer on the ADuCRF101 is implemented with the "wakeup" timer.
43  (timer 2). It should be clocked from an external crystal,
44  but if that doesn't seem to be present, this code will select the
45  imprecise internal 32.768 KHz oscillator instead. */
46 
47 static void
48 _timer2_enable(int enable)
49 {
50  T2CON_ENABLE_BBA = enable;
51  clock_time_t now = clock_time();
52  while(T2STA_CON_BBA) {
53  /* Synchronizing settings may fail if the chosen clock isn't running;
54  wait no more than 1ms for it */
55  if((clock_time() - now) > (CLOCK_SECOND / 1000)) {
56  break;
57  }
58  }
59 }
60 static uint32_t
61 _timer2_val(void)
62 {
63  /* This is atomic because the FREEZE bit is set in T2CON. */
64  uint32_t now;
65  now = pADI_WUT->T2VAL0;
66  now |= pADI_WUT->T2VAL1 << 16;
67  return now;
68 }
69 static uint32_t
70 _timer2_measure_freq(void)
71 {
72  const int test_usec = 10000;
73  uint32_t now = _timer2_val();
74  clock_delay_usec(test_usec);
75  return (_timer2_val() - now) * (1000000 / test_usec);
76 }
77 void
79 {
80  uint32_t freq;
81  const char *timer = "LFXTAL";
82 
83  _timer2_enable(0);
84  pADI_WUT->T2CON = T2CON_PRE_DIV1 | T2CON_MOD_FREERUN | T2CON_FREEZE_EN |
85  T2CON_WUEN_EN;
86 
87  /* Try 32.768 KHz crystal */
88  pADI_WUT->T2CON |= T2CON_CLK_LFXTAL;
89  _timer2_enable(1);
90  freq = _timer2_measure_freq();
91 
92  if(freq < 20000 || freq > 40000) {
93  /* No good; use 32.768 KHz internal oscillator */
94  _timer2_enable(0);
95  pADI_WUT->T2CON &= ~T2CON_CLK_MSK;
96  pADI_WUT->T2CON |= T2CON_CLK_LFOSC;
97  _timer2_enable(1);
98  freq = _timer2_measure_freq();
99  timer = "LFOSC";
100  }
101 
102  printf("Using %s for rtimer (%ld Hz)\n", timer, freq);
103 
104  /* Enable interrupt in NVIC, but disable in WUT for now. */
105  pADI_WUT->T2IEN = 0;
107 }
108 rtimer_clock_t
110 {
111  /* This is atomic because the FREEZE bit is set in T2CON. */
112  return _timer2_val();
113 }
114 void
115 rtimer_arch_schedule(rtimer_clock_t t)
116 {
117  uint32_t now = _timer2_val();
118 
119  /* Minimum of 5 wakeup timer ticks */
120  if((int32_t)(t - now) < 5) {
121  t = now + 5;
122  }
123 
124  /* Set T2WUFB to match at target time */
125  T2IEN_WUFB_BBA = 0;
126  pADI_WUT->T2WUFB0 = (t & 0xffff);
127  pADI_WUT->T2WUFB1 = (t >> 16);
128  T2IEN_WUFB_BBA = 1;
129 }
130 void
131 WakeUp_Int_Handler(void)
132 {
133  /* clear interrupt */
134  T2CLRI_WUFB_BBA = 1;
135  /* disable T2WUFB match */
136  T2IEN_WUFB_BBA = 0;
137  rtimer_run_next();
138 }
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
Enable External Interrupt.
Definition: core_cm0.h:535
A timer.
Definition: timer.h:86
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:94
void rtimer_arch_init(void)
We don&#39;t need to explicitly initialise anything but this routine is required by the API...
Definition: rtimer-arch.c:78
#define rtimer_arch_now()
Definition: rtimer-arch.h:40
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
void rtimer_arch_schedule(rtimer_clock_t t)
Schedules an rtimer task to be triggered at time t.
Definition: rtimer-arch.c:115
void rtimer_run_next(void)
Execute the next real-time task and schedule the next task, if any.
Definition: rtimer.c:92
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82