clock.c

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 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:33 2011 for Contiki 2.5 by  doxygen 1.6.1