Contiki 3.x
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 
33 #include "contiki-conf.h"
34 #include "sys/energest.h"
35 #include "sys/clock.h"
36 #include "sys/etimer.h"
37 #include "rtimer-arch.h"
38 #include "isr_compat.h"
39 
40 #include "dev/leds.h"
41 
42 #define INTERVAL (RTIMER_ARCH_SECOND / CLOCK_SECOND)
43 
44 #define MAX_TICKS (~((clock_time_t)0) / 2)
45 
46 #define CLOCK_LT(a, b) ((int16_t)((a)-(b)) < 0)
47 
48 static volatile unsigned long seconds;
49 
50 static volatile clock_time_t count = 0;
51 /* last_tar is used for calculating clock_fine, last_ccr might be better? */
52 static unsigned short last_tar = 0;
53 /*---------------------------------------------------------------------------*/
54 static inline uint16_t
55 read_tar(void)
56 {
57  /* Same as clock_counter(), but can be inlined */
58  uint16_t t1, t2;
59  do {
60  t1 = TA1R;
61  t2 = TA1R;
62  } while(t1 != t2);
63  return t1;
64 }
65 /*---------------------------------------------------------------------------*/
66 ISR(TIMER1_A1, timera1)
67 {
68  ENERGEST_ON(ENERGEST_TYPE_IRQ);
69 
70  if(TA1IV == 2) {
71 
72  /* HW timer bug fix: Interrupt handler called before TR==CCR.
73  * Occurrs when timer state is toggled between STOP and CONT. */
74  while(TA1CTL & MC1 && TA1CCR1 - TA1R == 1);
75 
76  last_tar = read_tar();
77  /* Make sure interrupt time is future */
78  while(!CLOCK_LT(last_tar, TA1CCR1)) {
79  /* TACTL &= ~MC1;*/
80  TA1CCR1 += INTERVAL;
81  /* TACTL |= MC1;*/
82  ++count;
83 
84  /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure
85  that the modulo operation below becomes a logical and and not
86  an expensive divide. Algorithm from Wikipedia:
87  http://en.wikipedia.org/wiki/Power_of_two */
88 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0
89 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...).
90 #error Change CLOCK_CONF_SECOND in contiki-conf.h.
91 #endif
92  if(count % CLOCK_CONF_SECOND == 0) {
93  ++seconds;
94  energest_flush();
95  }
96  last_tar = read_tar();
97  }
98 
99  if(etimer_pending() &&
100  (etimer_next_expiration_time() - count - 1) > MAX_TICKS) {
102  LPM4_EXIT;
103  }
104 
105  }
106  /* if(process_nevents() >= 0) {
107  LPM4_EXIT;
108  }*/
109 
110  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
111 }
112 /*---------------------------------------------------------------------------*/
113 clock_time_t
115 {
116  clock_time_t t1, t2;
117  do {
118  t1 = count;
119  t2 = count;
120  } while(t1 != t2);
121  return t1;
122 }
123 /*---------------------------------------------------------------------------*/
124 void
125 clock_set(clock_time_t clock, clock_time_t fclock)
126 {
127  TA1R = fclock;
128  TA1CCR1 = fclock + INTERVAL;
129  count = clock;
130 }
131 /*---------------------------------------------------------------------------*/
132 int
134 {
135  return INTERVAL;
136 }
137 /*---------------------------------------------------------------------------*/
138 unsigned short
139 clock_fine(void)
140 {
141  unsigned short t;
142  /* Assign last_tar to local varible that can not be changed by interrupt */
143  t = last_tar;
144  /* perform calc based on t, TAR will not be changed during interrupt */
145  return (unsigned short) (TA1R - t);
146 }
147 /*---------------------------------------------------------------------------*/
148 void
150 {
151  dint();
152 
153  /* Select SMCLK (2.4576MHz), clear TAR */
154  /* TACTL = TASSEL1 | TACLR | ID_3; */
155 
156  /* Select ACLK 32768Hz clock, divide by 2 */
157 /* TA1CTL = TASSEL0 | TACLR | ID_1; */
158 
159 #if INTERVAL==32768/CLOCK_SECOND
160  TA1CTL = TASSEL0 | TACLR;
161 #elif INTERVAL==16384/CLOCK_SECOND
162  TA1CTL = TASSEL0 | TACLR | ID_1;
163 #else
164 #error NEED TO UPDATE clock.c to match interval!
165 #endif
166 
167  /* Initialize ccr1 to create the X ms interval. */
168  /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */
169  TA1CCTL1 = CCIE;
170 
171  /* Interrupt after X ms. */
172  TA1CCR1 = INTERVAL;
173 
174  /* Start Timer_A in continuous mode. */
175  TA1CTL |= MC1;
176 
177  count = 0;
178 
179  /* Enable interrupts. */
180  eint();
181 
182 }
183 /*---------------------------------------------------------------------------*/
184 /**
185  * Delay the CPU for a multiple of 2.83 us.
186  */
187 void
188 clock_delay(unsigned int i)
189 {
190  /*
191  * This means that delay(i) will delay the CPU for CONST + 3x
192  * cycles. On a 2.4756 CPU, this means that each i adds 1.22us of
193  * delay.
194  *
195  * do {
196  * --i;
197  * } while(i > 0);
198  */
199 #ifdef __IAR_SYSTEMS_ICC__
200  asm("add #-1, r12");
201  asm("jnz $-2");
202 #else
203 #ifdef __GNUC__
204  asm("add #-1, r15");
205  asm("jnz $-2");
206 #else
207  do {
208  asm("nop");
209  --i;
210  } while(i > 0);
211 #endif /* __GNUC__ */
212 #endif /* __IAR_SYSTEMS_ICC__ */
213 }
214 /*---------------------------------------------------------------------------*/
215 #ifdef __GNUC__
216 void
217 __delay_cycles(unsigned long c)
218 {
219  c /= 4;
220  asm("add #-1, r15");
221  asm("jnz $-2");
222 }
223 #endif /* __GNUC__ */
224 /*---------------------------------------------------------------------------*/
225 /**
226  * Wait for a multiple of 10 ms.
227  *
228  */
229 void
230 clock_wait(clock_time_t i)
231 {
232  clock_time_t start;
233 
234  start = clock_time();
235  while(clock_time() - start < (clock_time_t)i);
236 }
237 /*---------------------------------------------------------------------------*/
238 void
239 clock_set_seconds(unsigned long sec)
240 {
241 
242 }
243 /*---------------------------------------------------------------------------*/
244 unsigned long
246 {
247  unsigned long t1, t2;
248  do {
249  t1 = seconds;
250  t2 = seconds;
251  } while(t1 != t2);
252  return t1;
253 }
254 /*---------------------------------------------------------------------------*/
255 rtimer_clock_t
256 clock_counter(void)
257 {
258  return TA1R;
259 }
260 /*---------------------------------------------------------------------------*/
void clock_init(void)
Initialize the clock library.
Definition: clock.c:76
Header file for the energy estimation mechanism
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
clock_time_t etimer_next_expiration_time(void)
Get next event timer expiration time.
Definition: etimer.c:229
#define __delay_cycles(x)
__delay_cycles() is an intrinsic IAR call; however, we have explicity disallowed it since it is too s...
Definition: gnu.h:169
void etimer_request_poll(void)
Make the event timer aware that the clock has changed.
Definition: etimer.c:145
void clock_set_seconds(unsigned long sec)
Set the value of the platform seconds.
Definition: clock.c:49
CCIF unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:57
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:223
void clock_delay(unsigned int delay)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock.c:60
void clock_wait(clock_time_t t)
Wait for a given number of ticks.
Definition: clock.c:166
Event timer header file.
int clock_fine_max(void)
Deprecated platform-specific routines.
Definition: clock.c:133