Contiki 2.6

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