Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2005, Swedish Institute of Computer Science 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * @(#)$Id: clock.c,v 1.25 2010/04/04 12:29:50 adamdunkels Exp $ 00032 */ 00033 00034 #include "contiki-conf.h" 00035 #include "sys/energest.h" 00036 #include "sys/clock.h" 00037 #include "sys/etimer.h" 00038 #include "rtimer-arch.h" 00039 #include "isr_compat.h" 00040 00041 #include "dev/leds.h" 00042 00043 #define INTERVAL (RTIMER_ARCH_SECOND / CLOCK_SECOND) 00044 00045 #define MAX_TICKS (~((clock_time_t)0) / 2) 00046 00047 static volatile unsigned long seconds; 00048 00049 static volatile clock_time_t count = 0; 00050 /* last_tar is used for calculating clock_fine, last_ccr might be better? */ 00051 static unsigned short last_tar = 0; 00052 /*---------------------------------------------------------------------------*/ 00053 ISR(TIMER1_A1, timera1) 00054 { 00055 ENERGEST_ON(ENERGEST_TYPE_IRQ); 00056 00057 if(TA1IV == 2) { 00058 00059 /* HW timer bug fix: Interrupt handler called before TR==CCR. 00060 * Occurrs when timer state is toggled between STOP and CONT. */ 00061 while(TA1CTL & MC1 && TA1CCR1 - TA1R == 1); 00062 00063 /* Make sure interrupt time is future */ 00064 do { 00065 /* TACTL &= ~MC1;*/ 00066 TA1CCR1 += INTERVAL; 00067 /* TACTL |= MC1;*/ 00068 ++count; 00069 00070 /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure 00071 that the modulo operation below becomes a logical and and not 00072 an expensive divide. Algorithm from Wikipedia: 00073 http://en.wikipedia.org/wiki/Power_of_two */ 00074 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0 00075 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...). 00076 #error Change CLOCK_CONF_SECOND in contiki-conf.h. 00077 #endif 00078 if(count % CLOCK_CONF_SECOND == 0) { 00079 ++seconds; 00080 energest_flush(); 00081 } 00082 } while((TA1CCR1 - TA1R) > INTERVAL); 00083 00084 last_tar = TA1R; 00085 00086 if(etimer_pending() && 00087 (etimer_next_expiration_time() - count - 1) > MAX_TICKS) { 00088 etimer_request_poll(); 00089 LPM4_EXIT; 00090 } 00091 00092 } 00093 /* if(process_nevents() >= 0) { 00094 LPM4_EXIT; 00095 }*/ 00096 00097 ENERGEST_OFF(ENERGEST_TYPE_IRQ); 00098 } 00099 /*---------------------------------------------------------------------------*/ 00100 clock_time_t 00101 clock_time(void) 00102 { 00103 clock_time_t t1, t2; 00104 do { 00105 t1 = count; 00106 t2 = count; 00107 } while(t1 != t2); 00108 return t1; 00109 } 00110 /*---------------------------------------------------------------------------*/ 00111 void 00112 clock_set(clock_time_t clock, clock_time_t fclock) 00113 { 00114 TA1R = fclock; 00115 TA1CCR1 = fclock + INTERVAL; 00116 count = clock; 00117 } 00118 /*---------------------------------------------------------------------------*/ 00119 int 00120 clock_fine_max(void) 00121 { 00122 return INTERVAL; 00123 } 00124 /*---------------------------------------------------------------------------*/ 00125 unsigned short 00126 clock_fine(void) 00127 { 00128 unsigned short t; 00129 /* Assign last_tar to local varible that can not be changed by interrupt */ 00130 t = last_tar; 00131 /* perform calc based on t, TAR will not be changed during interrupt */ 00132 return (unsigned short) (TA1R - t); 00133 } 00134 /*---------------------------------------------------------------------------*/ 00135 void 00136 clock_init(void) 00137 { 00138 dint(); 00139 00140 /* Select SMCLK (2.4576MHz), clear TAR */ 00141 /* TACTL = TASSEL1 | TACLR | ID_3; */ 00142 00143 /* Select ACLK 32768Hz clock, divide by 2 */ 00144 /* TA1CTL = TASSEL0 | TACLR | ID_1; */ 00145 00146 #if INTERVAL==32768/CLOCK_SECOND 00147 TA1CTL = TASSEL0 | TACLR; 00148 #elif INTERVAL==16384/CLOCK_SECOND 00149 TA1CTL = TASSEL0 | TACLR | ID_1; 00150 #else 00151 #error NEED TO UPDATE clock.c to match interval! 00152 #endif 00153 00154 /* Initialize ccr1 to create the X ms interval. */ 00155 /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */ 00156 TA1CCTL1 = CCIE; 00157 00158 /* Interrupt after X ms. */ 00159 TA1CCR1 = INTERVAL; 00160 00161 /* Start Timer_A in continuous mode. */ 00162 TA1CTL |= MC1; 00163 00164 count = 0; 00165 00166 /* Enable interrupts. */ 00167 eint(); 00168 00169 } 00170 /*---------------------------------------------------------------------------*/ 00171 /** 00172 * Delay the CPU for a multiple of 2.83 us. 00173 */ 00174 void 00175 clock_delay(unsigned int i) 00176 { 00177 /* 00178 * This means that delay(i) will delay the CPU for CONST + 3x 00179 * cycles. On a 2.4756 CPU, this means that each i adds 1.22us of 00180 * delay. 00181 * 00182 * do { 00183 * --i; 00184 * } while(i > 0); 00185 */ 00186 #ifdef __IAR_SYSTEMS_ICC__ 00187 asm("add #-1, r12"); 00188 asm("jnz $-2"); 00189 #else 00190 #ifdef __GNUC__ 00191 asm("add #-1, r15"); 00192 asm("jnz $-2"); 00193 #else 00194 do { 00195 asm("nop"); 00196 --i; 00197 } while(i > 0); 00198 #endif /* __GNUC__ */ 00199 #endif /* __IAR_SYSTEMS_ICC__ */ 00200 } 00201 /*---------------------------------------------------------------------------*/ 00202 #ifdef __GNUC__ 00203 void 00204 __delay_cycles(unsigned long c) 00205 { 00206 c /= 4; 00207 asm("add #-1, r15"); 00208 asm("jnz $-2"); 00209 } 00210 #endif /* __GNUC__ */ 00211 /*---------------------------------------------------------------------------*/ 00212 /** 00213 * Wait for a multiple of 10 ms. 00214 * 00215 */ 00216 void 00217 clock_wait(clock_time_t i) 00218 { 00219 clock_time_t start; 00220 00221 start = clock_time(); 00222 while(clock_time() - start < (clock_time_t)i); 00223 } 00224 /*---------------------------------------------------------------------------*/ 00225 void 00226 clock_set_seconds(unsigned long sec) 00227 { 00228 00229 } 00230 /*---------------------------------------------------------------------------*/ 00231 unsigned long 00232 clock_seconds(void) 00233 { 00234 unsigned long t1, t2; 00235 do { 00236 t1 = seconds; 00237 t2 = seconds; 00238 } while(t1 != t2); 00239 return t1; 00240 } 00241 /*---------------------------------------------------------------------------*/ 00242 rtimer_clock_t 00243 clock_counter(void) 00244 { 00245 return TA1R; 00246 } 00247 /*---------------------------------------------------------------------------*/