Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2009, 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 /** 00033 * \file 00034 * Implementation of the clock functions for the cc253x. 00035 * Ported over from the cc243x original. 00036 * \author 00037 * Zach Shelby (zach@sensinode.com) - original (cc243x) 00038 * George Oikonomou - <oikonomou@users.sourceforge.net> - cc2530 port 00039 */ 00040 #include "sfr-bits.h" 00041 #include "sys/clock.h" 00042 #include "sys/etimer.h" 00043 #include "cc253x.h" 00044 #include "sys/energest.h" 00045 00046 /* Sleep timer runs on the 32k RC osc. */ 00047 /* One clock tick is 7.8 ms */ 00048 #define TICK_VAL (32768/128) /* 256 */ 00049 /*---------------------------------------------------------------------------*/ 00050 #if CLOCK_CONF_STACK_FRIENDLY 00051 volatile __bit sleep_flag; 00052 #else 00053 #endif 00054 /*---------------------------------------------------------------------------*/ 00055 /* Do NOT remove the absolute address and do NOT remove the initialiser here */ 00056 __xdata __at(0x0000) static unsigned long timer_value = 0; 00057 00058 static volatile __data clock_time_t count = 0; /* Uptime in ticks */ 00059 static volatile __data clock_time_t seconds = 0; /* Uptime in secs */ 00060 /*---------------------------------------------------------------------------*/ 00061 /** 00062 * Each iteration is ~1.0xy usec, so this function delays for roughly len usec 00063 */ 00064 void 00065 clock_delay_usec(uint16_t len) 00066 { 00067 DISABLE_INTERRUPTS(); 00068 while(len--) { 00069 ASM(nop); 00070 } 00071 ENABLE_INTERRUPTS(); 00072 } 00073 /*---------------------------------------------------------------------------*/ 00074 /** 00075 * Wait for a multiple of ~8 ms (a tick) 00076 */ 00077 void 00078 clock_wait(clock_time_t i) 00079 { 00080 clock_time_t start; 00081 00082 start = clock_time(); 00083 while(clock_time() - start < (clock_time_t)i); 00084 } 00085 /*---------------------------------------------------------------------------*/ 00086 CCIF clock_time_t 00087 clock_time(void) 00088 { 00089 return count; 00090 } 00091 /*---------------------------------------------------------------------------*/ 00092 CCIF unsigned long 00093 clock_seconds(void) 00094 { 00095 return seconds; 00096 } 00097 /*---------------------------------------------------------------------------*/ 00098 /* 00099 * There is some ambiguity between TI cc2530 software examples and information 00100 * in the datasheet. 00101 * 00102 * TI examples appear to be writing to SLEEPCMD, initialising hardware in a 00103 * fashion semi-similar to cc2430 00104 * 00105 * However, the datasheet claims that those bits in SLEEPCMD are reserved 00106 * 00107 * The code here goes by the datasheet (ignore TI examples) and seems to work. 00108 */ 00109 void 00110 clock_init(void) 00111 { 00112 /* Make sure we know where we stand */ 00113 CLKCONCMD = CLKCONCMD_OSC32K | CLKCONCMD_OSC; 00114 00115 /* Stay with 32 KHz RC OSC, Chance System Clock to 32 MHz */ 00116 CLKCONCMD &= ~CLKCONCMD_OSC; 00117 while(CLKCONSTA & CLKCONCMD_OSC); 00118 00119 /* Tickspeed 500 kHz for timers[1-4] */ 00120 CLKCONCMD |= CLKCONCMD_TICKSPD2 | CLKCONCMD_TICKSPD1; 00121 while(CLKCONSTA != CLKCONCMD); 00122 00123 /* Initialize tick value */ 00124 timer_value = ST0; 00125 timer_value += ((unsigned long int) ST1) << 8; 00126 timer_value += ((unsigned long int) ST2) << 16; 00127 timer_value += TICK_VAL; 00128 ST2 = (unsigned char) (timer_value >> 16); 00129 ST1 = (unsigned char) (timer_value >> 8); 00130 ST0 = (unsigned char) timer_value; 00131 00132 STIE = 1; /* IEN0.STIE interrupt enable */ 00133 } 00134 /*---------------------------------------------------------------------------*/ 00135 void 00136 clock_isr(void) __interrupt(ST_VECTOR) 00137 { 00138 DISABLE_INTERRUPTS(); 00139 ENERGEST_ON(ENERGEST_TYPE_IRQ); 00140 00141 /* 00142 * Read value of the ST0:ST1:ST2, add TICK_VAL and write it back. 00143 * Next interrupt occurs after the current time + TICK_VAL 00144 */ 00145 timer_value = ST0; 00146 timer_value += ((unsigned long int) ST1) << 8; 00147 timer_value += ((unsigned long int) ST2) << 16; 00148 timer_value += TICK_VAL; 00149 ST2 = (unsigned char) (timer_value >> 16); 00150 ST1 = (unsigned char) (timer_value >> 8); 00151 ST0 = (unsigned char) timer_value; 00152 00153 ++count; 00154 00155 /* Make sure the CLOCK_CONF_SECOND is a power of two, to ensure 00156 that the modulo operation below becomes a logical and and not 00157 an expensive divide. Algorithm from Wikipedia: 00158 http://en.wikipedia.org/wiki/Power_of_two */ 00159 #if (CLOCK_CONF_SECOND & (CLOCK_CONF_SECOND - 1)) != 0 00160 #error CLOCK_CONF_SECOND must be a power of two (i.e., 1, 2, 4, 8, 16, 32, 64, ...). 00161 #error Change CLOCK_CONF_SECOND in contiki-conf.h. 00162 #endif 00163 if(count % CLOCK_CONF_SECOND == 0) { 00164 ++seconds; 00165 } 00166 00167 #if CLOCK_CONF_STACK_FRIENDLY 00168 sleep_flag = 1; 00169 #else 00170 if(etimer_pending() 00171 && (etimer_next_expiration_time() - count - 1) > MAX_TICKS) { 00172 etimer_request_poll(); 00173 } 00174 #endif 00175 00176 STIF = 0; /* IRCON.STIF */ 00177 ENERGEST_OFF(ENERGEST_TYPE_IRQ); 00178 ENABLE_INTERRUPTS(); 00179 } 00180 /*---------------------------------------------------------------------------*/