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  * @(#)$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 /*---------------------------------------------------------------------------*/