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.26 2010/12/16 22:50:21 adamdunkels Exp $ 00032 */ 00033 00034 00035 #include <io.h> 00036 #include <signal.h> 00037 00038 #include "contiki-conf.h" 00039 00040 #include "sys/energest.h" 00041 #include "sys/clock.h" 00042 #include "sys/etimer.h" 00043 #include "rtimer-arch.h" 00044 #include "watchdog.h" 00045 00046 #define INTERVAL (RTIMER_ARCH_SECOND / CLOCK_SECOND) 00047 00048 #define MAX_TICKS (~((clock_time_t)0) / 2) 00049 00050 static volatile unsigned long seconds; 00051 00052 static volatile clock_time_t count = 0; 00053 /* last_tar is used for calculating clock_fine */ 00054 static volatile uint16_t last_tar = 0; 00055 /*---------------------------------------------------------------------------*/ 00056 interrupt(TIMERA1_VECTOR) timera1 (void) { 00057 ENERGEST_ON(ENERGEST_TYPE_IRQ); 00058 00059 watchdog_start(); 00060 00061 if(TAIV == 2) { 00062 00063 /* HW timer bug fix: Interrupt handler called before TR==CCR. 00064 * Occurrs when timer state is toggled between STOP and CONT. */ 00065 while(TACTL & MC1 && TACCR1 - TAR == 1); 00066 00067 /* Make sure interrupt time is future */ 00068 do { 00069 TACCR1 += INTERVAL; 00070 ++count; 00071 00072 /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure 00073 that the modulo operation below becomes a logical and and not 00074 an expensive divide. Algorithm from Wikipedia: 00075 http://en.wikipedia.org/wiki/Power_of_two */ 00076 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0 00077 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...). 00078 #error Change CLOCK_CONF_SECOND in contiki-conf.h. 00079 #endif 00080 if(count % CLOCK_CONF_SECOND == 0) { 00081 ++seconds; 00082 energest_flush(); 00083 } 00084 } while((TACCR1 - TAR) > INTERVAL); 00085 00086 last_tar = TAR; 00087 00088 if(etimer_pending() && 00089 (etimer_next_expiration_time() - count - 1) > MAX_TICKS) { 00090 etimer_request_poll(); 00091 LPM4_EXIT; 00092 } 00093 00094 } 00095 /* if(process_nevents() >= 0) { 00096 LPM4_EXIT; 00097 }*/ 00098 00099 watchdog_stop(); 00100 00101 ENERGEST_OFF(ENERGEST_TYPE_IRQ); 00102 } 00103 /*---------------------------------------------------------------------------*/ 00104 clock_time_t 00105 clock_time(void) 00106 { 00107 clock_time_t t1, t2; 00108 do { 00109 t1 = count; 00110 t2 = count; 00111 } while(t1 != t2); 00112 return t1; 00113 } 00114 /*---------------------------------------------------------------------------*/ 00115 void 00116 clock_set(clock_time_t clock, clock_time_t fclock) 00117 { 00118 TAR = fclock; 00119 TACCR1 = fclock + INTERVAL; 00120 count = clock; 00121 } 00122 /*---------------------------------------------------------------------------*/ 00123 int 00124 clock_fine_max(void) 00125 { 00126 return INTERVAL; 00127 } 00128 /*---------------------------------------------------------------------------*/ 00129 unsigned short 00130 clock_fine(void) 00131 { 00132 unsigned short t; 00133 /* Assign last_tar to local varible that can not be changed by interrupt */ 00134 t = last_tar; 00135 /* perform calc based on t, TAR will not be changed during interrupt */ 00136 return (unsigned short) (TAR - t); 00137 } 00138 /*---------------------------------------------------------------------------*/ 00139 void 00140 clock_init(void) 00141 { 00142 dint(); 00143 00144 /* Select SMCLK (2.4576MHz), clear TAR */ 00145 /* TACTL = TASSEL1 | TACLR | ID_3; */ 00146 00147 /* Select ACLK 32768Hz clock, divide by 2 */ 00148 /* TACTL = TASSEL0 | TACLR | ID_1;*/ 00149 00150 /* Select ACLK 32768Hz clock */ 00151 TACTL = TASSEL0 | TACLR; 00152 00153 /* Initialize ccr1 to create the X ms interval. */ 00154 /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */ 00155 TACCTL1 = CCIE; 00156 00157 /* Interrupt after X ms. */ 00158 TACCR1 = INTERVAL; 00159 00160 /* Start Timer_A in continuous mode. */ 00161 TACTL |= MC1; 00162 00163 count = 0; 00164 00165 /* Enable interrupts. */ 00166 eint(); 00167 00168 } 00169 /*---------------------------------------------------------------------------*/ 00170 /** 00171 * Delay the CPU for a multiple of 2.83 us. 00172 */ 00173 void 00174 clock_delay(unsigned int i) 00175 { 00176 asm("add #-1, r15"); 00177 asm("jnz $-2"); 00178 /* 00179 * This means that delay(i) will delay the CPU for CONST + 3x 00180 * cycles. On a 2.4756 CPU, this means that each i adds 1.22us of 00181 * delay. 00182 * 00183 * do { 00184 * --i; 00185 * } while(i > 0); 00186 */ 00187 } 00188 /*---------------------------------------------------------------------------*/ 00189 /** 00190 * Wait for a multiple of 10 ms. 00191 * 00192 */ 00193 void 00194 clock_wait(int i) 00195 { 00196 clock_time_t start; 00197 00198 start = clock_time(); 00199 while(clock_time() - start < (clock_time_t)i); 00200 } 00201 /*---------------------------------------------------------------------------*/ 00202 void 00203 clock_set_seconds(unsigned long sec) 00204 { 00205 00206 } 00207 /*---------------------------------------------------------------------------*/ 00208 unsigned long 00209 clock_seconds(void) 00210 { 00211 unsigned long t1, t2; 00212 do { 00213 t1 = seconds; 00214 t2 = seconds; 00215 } while(t1 != t2); 00216 return t1; 00217 } 00218 /*---------------------------------------------------------------------------*/ 00219 rtimer_clock_t 00220 clock_counter(void) 00221 { 00222 return TAR; 00223 } 00224 /*---------------------------------------------------------------------------*/