Contiki 2.6

clock.c

00001 /*
00002  * Copyright (c) 2011, 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, last_ccr might be better? */
00048 static volatile uint16_t last_tar = 0;
00049 /*---------------------------------------------------------------------------*/
00050 ISR(TIMER1_A1, timera1)
00051 {
00052   ENERGEST_ON(ENERGEST_TYPE_IRQ);
00053 
00054   /* watchdog_start(); */
00055 
00056   if(TA1IV == 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(TA1CTL & MC1 && TA1CCR1 - TA1R == 1);
00061 
00062     /* Make sure interrupt time is future */
00063     do {
00064       TA1CCR1 += 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((TA1CCR1 - TA1R) > INTERVAL);
00080 
00081     last_tar = TA1R;
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   TA1R = fclock;
00114   TA1CCR1 = 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) (TA1R - 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 /*   TA1CTL = TASSEL0 | TACLR | ID_1; */
00144 
00145 #if INTERVAL==32768/CLOCK_SECOND
00146   TA1CTL = TASSEL0 | TACLR;
00147 #elif INTERVAL==16384/CLOCK_SECOND
00148   TA1CTL = TASSEL0 | TACLR | ID_1;
00149 #else
00150 #error NEED TO UPDATE clock.c to match interval!
00151 #endif
00152 
00153   /* Initialize ccr1 to create the X ms interval. */
00154   /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */
00155   TA1CCTL1 = CCIE;
00156 
00157   /* Interrupt after X ms. */
00158   TA1CCR1 = INTERVAL;
00159 
00160   /* Start Timer_A in continuous mode. */
00161   TA1CTL |= 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   while(i--) {
00177     _NOP();
00178   }
00179 }
00180 /*---------------------------------------------------------------------------*/
00181 /**
00182  * Wait for a multiple of 10 ms.
00183  *
00184  */
00185 void
00186 clock_wait(clock_time_t i)
00187 {
00188   clock_time_t start;
00189 
00190   start = clock_time();
00191   while(clock_time() - start < (clock_time_t)i);
00192 }
00193 /*---------------------------------------------------------------------------*/
00194 void
00195 clock_set_seconds(unsigned long sec)
00196 {
00197   int s;
00198   s = splhigh();
00199   seconds = sec;
00200   splx(s);
00201 }
00202 /*---------------------------------------------------------------------------*/
00203 unsigned long
00204 clock_seconds(void)
00205 {
00206   unsigned long t1, t2;
00207   do {
00208     t1 = seconds;
00209     t2 = seconds;
00210   } while(t1 != t2);
00211   return t1;
00212 }
00213 /*---------------------------------------------------------------------------*/
00214 rtimer_clock_t
00215 clock_counter(void)
00216 {
00217   rtimer_clock_t t1, t2;
00218   do {
00219     t1 = TA1R;
00220     t2 = TA1R;
00221   } while(t1 != t2);
00222   return t1;
00223 }
00224 /*---------------------------------------------------------------------------*/