Contiki 2.5
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  * @(#)$Id: clock.c,v 1.26 2010/12/16 22:50:21 adamdunkels Exp $
32  */
33 
34 
35 #include "contiki.h"
36 #include "sys/energest.h"
37 #include "sys/clock.h"
38 #include "sys/etimer.h"
39 #include "rtimer-arch.h"
40 #include "watchdog.h"
41 
42 #define INTERVAL (RTIMER_ARCH_SECOND / CLOCK_SECOND)
43 
44 #define MAX_TICKS (~((clock_time_t)0) / 2)
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 #ifdef __IAR_SYSTEMS_ICC__
53 #pragma vector=TIMERA1_VECTOR
54 __interrupt void
55 #else
56 interrupt(TIMERA1_VECTOR)
57 #endif
58 timera1 (void) {
59  ENERGEST_ON(ENERGEST_TYPE_IRQ);
60 
61  watchdog_start();
62 
63  if(TAIV == 2) {
64 
65  /* HW timer bug fix: Interrupt handler called before TR==CCR.
66  * Occurrs when timer state is toggled between STOP and CONT. */
67  while(TACTL & MC1 && TACCR1 - TAR == 1);
68 
69  /* Make sure interrupt time is future */
70  do {
71  TACCR1 += INTERVAL;
72  ++count;
73 
74  /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure
75  that the modulo operation below becomes a logical and and not
76  an expensive divide. Algorithm from Wikipedia:
77  http://en.wikipedia.org/wiki/Power_of_two */
78 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0
79 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...).
80 #error Change CLOCK_CONF_SECOND in contiki-conf.h.
81 #endif
82  if(count % CLOCK_CONF_SECOND == 0) {
83  ++seconds;
84  energest_flush();
85  }
86  } while((TACCR1 - TAR) > INTERVAL);
87 
88  last_tar = TAR;
89 
90  if(etimer_pending() &&
91  (etimer_next_expiration_time() - count - 1) > MAX_TICKS) {
93  LPM4_EXIT;
94  }
95 
96  }
97  /* if(process_nevents() >= 0) {
98  LPM4_EXIT;
99  }*/
100 
101  watchdog_stop();
102 
103  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
104 }
105 /*---------------------------------------------------------------------------*/
106 clock_time_t
108 {
109  clock_time_t t1, t2;
110  do {
111  t1 = count;
112  t2 = count;
113  } while(t1 != t2);
114  return t1;
115 }
116 /*---------------------------------------------------------------------------*/
117 void
118 clock_set(clock_time_t clock, clock_time_t fclock)
119 {
120  TAR = fclock;
121  TACCR1 = fclock + INTERVAL;
122  count = clock;
123 }
124 /*---------------------------------------------------------------------------*/
125 int
126 clock_fine_max(void)
127 {
128  return INTERVAL;
129 }
130 /*---------------------------------------------------------------------------*/
131 unsigned short
132 clock_fine(void)
133 {
134  unsigned short t;
135  /* Assign last_tar to local varible that can not be changed by interrupt */
136  t = last_tar;
137  /* perform calc based on t, TAR will not be changed during interrupt */
138  return (unsigned short) (TAR - t);
139 }
140 /*---------------------------------------------------------------------------*/
141 void
143 {
144  dint();
145 
146  /* Select SMCLK (2.4576MHz), clear TAR */
147  /* TACTL = TASSEL1 | TACLR | ID_3; */
148 
149  /* Select ACLK 32768Hz clock, divide by 2 */
150  /* TACTL = TASSEL0 | TACLR | ID_1;*/
151 
152  /* Select ACLK 32768Hz clock */
153  TACTL = TASSEL0 | TACLR;
154 
155  /* Initialize ccr1 to create the X ms interval. */
156  /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */
157  TACCTL1 = CCIE;
158 
159  /* Interrupt after X ms. */
160  TACCR1 = INTERVAL;
161 
162  /* Start Timer_A in continuous mode. */
163  TACTL |= MC1;
164 
165  count = 0;
166 
167  /* Enable interrupts. */
168  eint();
169 
170 }
171 /*---------------------------------------------------------------------------*/
172 /**
173  * Delay the CPU for a multiple of 2.83 us.
174  */
175 void
176 clock_delay(unsigned int i)
177 {
178  asm("add #-1, r15");
179  asm("jnz $-2");
180  /*
181  * This means that delay(i) will delay the CPU for CONST + 3x
182  * cycles. On a 2.4756 CPU, this means that each i adds 1.22us of
183  * delay.
184  *
185  * do {
186  * --i;
187  * } while(i > 0);
188  */
189 }
190 /*---------------------------------------------------------------------------*/
191 /**
192  * Wait for a multiple of 10 ms.
193  *
194  */
195 void
196 clock_wait(int i)
197 {
198  clock_time_t start;
199 
200  start = clock_time();
201  while(clock_time() - start < (clock_time_t)i);
202 }
203 /*---------------------------------------------------------------------------*/
204 void
205 clock_set_seconds(unsigned long sec)
206 {
207 
208 }
209 /*---------------------------------------------------------------------------*/
210 unsigned long
211 clock_seconds(void)
212 {
213  unsigned long t1, t2;
214  do {
215  t1 = seconds;
216  t2 = seconds;
217  } while(t1 != t2);
218  return t1;
219 }
220 /*---------------------------------------------------------------------------*/
221 rtimer_clock_t
222 clock_counter(void)
223 {
224  return TAR;
225 }
226 /*---------------------------------------------------------------------------*/