Contiki-NG
clock.c
1 /*
2  * Copyright (c) 2005, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 #include "contiki.h"
33 #include "sys/clock.h"
34 #include "sys/etimer.h"
35 #include "sys/energest.h"
36 #include "rtimer-arch.h"
37 #include "dev/watchdog.h"
38 #include "isr_compat.h"
39 
40 #define INTERVAL (RTIMER_ARCH_SECOND / CLOCK_SECOND)
41 
42 #define MAX_TICKS (~((clock_time_t)0) / 2)
43 
44 #define CLOCK_LT(a, b) ((int16_t)((a)-(b)) < 0)
45 
46 static volatile unsigned long seconds;
47 
48 static volatile clock_time_t count = 0;
49 /* last_tar is used for calculating clock_fine */
50 static volatile uint16_t last_tar = 0;
51 /*---------------------------------------------------------------------------*/
52 static inline uint16_t
53 read_tar(void)
54 {
55  /* Same as clock_counter(), but can be inlined */
56  uint16_t t1, t2;
57  do {
58  t1 = TAR;
59  t2 = TAR;
60  } while(t1 != t2);
61  return t1;
62 }
63 /*---------------------------------------------------------------------------*/
64 ISR(TIMERA1, timera1)
65 {
67 
68  if(TAIV == 2) {
69 
70  /* HW timer bug fix: Interrupt handler called before TR==CCR.
71  * Occurs when timer state is toggled between STOP and CONT. */
72  while(TACTL & MC1 && TACCR1 - read_tar() == 1);
73 
74  last_tar = read_tar();
75  /* Make sure interrupt time is future */
76  while(!CLOCK_LT(last_tar, TACCR1)) {
77  TACCR1 += INTERVAL;
78  ++count;
79 
80  /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure
81  that the modulo operation below becomes a logical and and not
82  an expensive divide. Algorithm from Wikipedia:
83  http://en.wikipedia.org/wiki/Power_of_two */
84 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0
85 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...).
86 #error Change CLOCK_CONF_SECOND in contiki-conf.h.
87 #endif
88  if(count % CLOCK_CONF_SECOND == 0) {
89  ++seconds;
90  energest_flush();
91  }
92  last_tar = read_tar();
93  }
94 
95  if(etimer_pending() &&
96  (etimer_next_expiration_time() - count - 1) > MAX_TICKS) {
98  LPM4_EXIT;
99  }
100 
101  }
102  /* if(process_nevents() >= 0) {
103  LPM4_EXIT;
104  }*/
105 
106  watchdog_stop();
107 }
108 /*---------------------------------------------------------------------------*/
109 clock_time_t
111 {
112  clock_time_t t1, t2;
113  do {
114  t1 = count;
115  t2 = count;
116  } while(t1 != t2);
117  return t1;
118 }
119 /*---------------------------------------------------------------------------*/
120 void
121 clock_set(clock_time_t clock, clock_time_t fclock)
122 {
123  TAR = fclock;
124  TACCR1 = fclock + INTERVAL;
125  count = clock;
126 }
127 /*---------------------------------------------------------------------------*/
128 int
130 {
131  return INTERVAL;
132 }
133 /*---------------------------------------------------------------------------*/
134 unsigned short
135 clock_fine(void)
136 {
137  unsigned short t;
138  /* Assign last_tar to local varible that can not be changed by interrupt */
139  t = last_tar;
140  /* perform calc based on t, TAR will not be changed during interrupt */
141  return (unsigned short) (TAR - t);
142 }
143 /*---------------------------------------------------------------------------*/
144 void
146 {
147  dint();
148 
149  /* Select SMCLK (2.4576MHz), clear TAR */
150  /* TACTL = TASSEL1 | TACLR | ID_3; */
151 
152  /* Select ACLK 32768Hz clock, divide by 2 */
153  /* TACTL = TASSEL0 | TACLR | ID_1;*/
154 
155  /* Select ACLK 32768Hz clock */
156  /* TACTL = TASSEL0 | TACLR; */
157 
158 #if INTERVAL==32768/CLOCK_SECOND
159  TACTL = TASSEL0 | TACLR;
160 #elif INTERVAL==16384/CLOCK_SECOND
161  TACTL = TASSEL0 | TACLR | ID_1;
162 #else
163 #error NEED TO UPDATE clock.c to match interval!
164 #endif
165 
166  /* Initialize ccr1 to create the X ms interval. */
167  /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR. */
168  TACCTL1 = CCIE;
169 
170  /* Interrupt after X ms. */
171  TACCR1 = INTERVAL;
172 
173  /* Start Timer_A in continuous mode. */
174  TACTL |= MC1;
175 
176  count = 0;
177 
178  /* Enable interrupts. */
179  eint();
180 
181 }
182 /*---------------------------------------------------------------------------*/
183 /**
184  * Delay the CPU for a multiple of 2.83 us.
185  */
186 void
187 clock_delay(unsigned int i)
188 {
189  while(i--) {
190  _NOP();
191  }
192 }
193 /*---------------------------------------------------------------------------*/
194 /*
195  * Wait for a multiple of 10 ms.
196  *
197  */
198 void
199 clock_wait(clock_time_t i)
200 {
201  clock_time_t start;
202 
203  start = clock_time();
204  while(clock_time() - start < (clock_time_t)i);
205 }
206 /*---------------------------------------------------------------------------*/
207 void
208 clock_set_seconds(unsigned long sec)
209 {
210  int s;
211  s = splhigh();
212  seconds = sec;
213  splx(s);
214 }
215 /*---------------------------------------------------------------------------*/
216 unsigned long
218 {
219  unsigned long t1, t2;
220  do {
221  t1 = seconds;
222  t2 = seconds;
223  } while(t1 != t2);
224  return t1;
225 }
226 /*---------------------------------------------------------------------------*/
227 rtimer_clock_t
228 clock_counter(void)
229 {
230  rtimer_clock_t t1, t2;
231  do {
232  t1 = TAR;
233  t2 = TAR;
234  } while(t1 != t2);
235  return t1;
236 }
237 /*---------------------------------------------------------------------------*/
Header file for the energy estimation mechanism
void etimer_request_poll(void)
Make the event timer aware that the clock has changed.
Definition: etimer.c:145
void clock_wait(clock_time_t i)
Wait for a given number of ticks.
Definition: clock.c:136
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:130
clock_time_t etimer_next_expiration_time(void)
Get next event timer expiration time.
Definition: etimer.c:237
int clock_fine_max(void)
Deprecated platform-specific routines.
Definition: clock.c:129
static void start(void)
Start measurement.
void watchdog_start(void)
Starts the WDT in watchdog mode if enabled by user configuration, maximum interval.
Definition: watchdog.c:72
Event timer header file.
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:231
void clock_delay(unsigned int i)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock.c:164
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
void clock_set_seconds(unsigned long sec)
Set the value of the platform seconds.
Definition: clock.c:124
void clock_init(void)
Arch-specific implementation of clock_init for the cc2538.
Definition: clock.c:93
void watchdog_stop(void)
Stops the WDT such that it won&#39;t timeout and cause MCU reset.