Contiki-Inga 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 static volatile unsigned long seconds;
47 
48 static volatile clock_time_t count = 0;
49 /* last_tar is used for calculating clock_fine, last_ccr might be better? */
50 static unsigned short last_tar = 0;
51 /*---------------------------------------------------------------------------*/
52 ISR(TIMER1_A1, timera1)
53 {
54  ENERGEST_ON(ENERGEST_TYPE_IRQ);
55 
56  if(TA1IV == 2) {
57 
58  /* HW timer bug fix: Interrupt handler called before TR==CCR.
59  * Occurrs when timer state is toggled between STOP and CONT. */
60  while(TA1CTL & MC1 && TA1CCR1 - TA1R == 1);
61 
62  /* Make sure interrupt time is future */
63  do {
64  /* TACTL &= ~MC1;*/
65  TA1CCR1 += INTERVAL;
66  /* TACTL |= MC1;*/
67  ++count;
68 
69  /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure
70  that the modulo operation below becomes a logical and and not
71  an expensive divide. Algorithm from Wikipedia:
72  http://en.wikipedia.org/wiki/Power_of_two */
73 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0
74 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...).
75 #error Change CLOCK_CONF_SECOND in contiki-conf.h.
76 #endif
77  if(count % CLOCK_CONF_SECOND == 0) {
78  ++seconds;
79  energest_flush();
80  }
81  } while((TA1CCR1 - TA1R) > INTERVAL);
82 
83  last_tar = TA1R;
84 
85  if(etimer_pending() &&
86  (etimer_next_expiration_time() - count - 1) > MAX_TICKS) {
88  LPM4_EXIT;
89  }
90 
91  }
92  /* if(process_nevents() >= 0) {
93  LPM4_EXIT;
94  }*/
95 
96  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
97 }
98 /*---------------------------------------------------------------------------*/
99 clock_time_t
101 {
102  clock_time_t t1, t2;
103  do {
104  t1 = count;
105  t2 = count;
106  } while(t1 != t2);
107  return t1;
108 }
109 /*---------------------------------------------------------------------------*/
110 void
111 clock_set(clock_time_t clock, clock_time_t fclock)
112 {
113  TA1R = fclock;
114  TA1CCR1 = fclock + INTERVAL;
115  count = clock;
116 }
117 /*---------------------------------------------------------------------------*/
118 int
120 {
121  return INTERVAL;
122 }
123 /*---------------------------------------------------------------------------*/
124 unsigned short
125 clock_fine(void)
126 {
127  unsigned short t;
128  /* Assign last_tar to local varible that can not be changed by interrupt */
129  t = last_tar;
130  /* perform calc based on t, TAR will not be changed during interrupt */
131  return (unsigned short) (TA1R - t);
132 }
133 /*---------------------------------------------------------------------------*/
134 void
136 {
137  dint();
138 
139  /* Select SMCLK (2.4576MHz), clear TAR */
140  /* TACTL = TASSEL1 | TACLR | ID_3; */
141 
142  /* Select ACLK 32768Hz clock, divide by 2 */
143 /* TA1CTL = TASSEL0 | TACLR | ID_1; */
144 
145 #if INTERVAL==32768/CLOCK_SECOND
146  TA1CTL = TASSEL0 | TACLR;
147 #elif INTERVAL==16384/CLOCK_SECOND
148  TA1CTL = TASSEL0 | TACLR | ID_1;
149 #else
150 #error NEED TO UPDATE clock.c to match interval!
151 #endif
152 
153  /* Initialize ccr1 to create the X ms interval. */
154  /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */
155  TA1CCTL1 = CCIE;
156 
157  /* Interrupt after X ms. */
158  TA1CCR1 = INTERVAL;
159 
160  /* Start Timer_A in continuous mode. */
161  TA1CTL |= MC1;
162 
163  count = 0;
164 
165  /* Enable interrupts. */
166  eint();
167 
168 }
169 /*---------------------------------------------------------------------------*/
170 /**
171  * Delay the CPU for a multiple of 2.83 us.
172  */
173 void
174 clock_delay(unsigned int i)
175 {
176  /*
177  * This means that delay(i) will delay the CPU for CONST + 3x
178  * cycles. On a 2.4756 CPU, this means that each i adds 1.22us of
179  * delay.
180  *
181  * do {
182  * --i;
183  * } while(i > 0);
184  */
185 #ifdef __IAR_SYSTEMS_ICC__
186  asm("add #-1, r12");
187  asm("jnz $-2");
188 #else
189 #ifdef __GNUC__
190  asm("add #-1, r15");
191  asm("jnz $-2");
192 #else
193  do {
194  asm("nop");
195  --i;
196  } while(i > 0);
197 #endif /* __GNUC__ */
198 #endif /* __IAR_SYSTEMS_ICC__ */
199 }
200 /*---------------------------------------------------------------------------*/
201 #ifdef __GNUC__
202 void
203 __delay_cycles(unsigned long c)
204 {
205  c /= 4;
206  asm("add #-1, r15");
207  asm("jnz $-2");
208 }
209 #endif /* __GNUC__ */
210 /*---------------------------------------------------------------------------*/
211 /**
212  * Wait for a multiple of 10 ms.
213  *
214  */
215 void
216 clock_wait(clock_time_t i)
217 {
218  clock_time_t start;
219 
220  start = clock_time();
221  while(clock_time() - start < (clock_time_t)i);
222 }
223 /*---------------------------------------------------------------------------*/
224 void
225 clock_set_seconds(unsigned long sec)
226 {
227 
228 }
229 /*---------------------------------------------------------------------------*/
230 unsigned long
232 {
233  unsigned long t1, t2;
234  do {
235  t1 = seconds;
236  t2 = seconds;
237  } while(t1 != t2);
238  return t1;
239 }
240 /*---------------------------------------------------------------------------*/
241 rtimer_clock_t
242 clock_counter(void)
243 {
244  return TA1R;
245 }
246 /*---------------------------------------------------------------------------*/