Contiki 2.6
|
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 "dev/watchdog.h" 00034 00035 /* dco_required set to 1 will cause the CPU not to go into 00036 sleep modes where the DCO clock stopped */ 00037 int msp430_dco_required; 00038 00039 #if defined(__MSP430__) && defined(__GNUC__) 00040 #define asmv(arg) __asm__ __volatile__(arg) 00041 #endif 00042 00043 /*---------------------------------------------------------------------------*/ 00044 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND 00045 void * 00046 w_memcpy(void *out, const void *in, size_t n) 00047 { 00048 uint8_t *src, *dest; 00049 src = (uint8_t *) in; 00050 dest = (uint8_t *) out; 00051 while(n-- > 0) { 00052 *dest++ = *src++; 00053 } 00054 return out; 00055 } 00056 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */ 00057 /*---------------------------------------------------------------------------*/ 00058 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND 00059 void * 00060 w_memset(void *out, int value, size_t n) 00061 { 00062 uint8_t *dest; 00063 dest = (uint8_t *) out; 00064 while(n-- > 0) { 00065 *dest++ = value & 0xff; 00066 } 00067 return out; 00068 } 00069 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */ 00070 /*---------------------------------------------------------------------------*/ 00071 void 00072 msp430_init_dco(void) 00073 { 00074 /* This code taken from the FU Berlin sources and reformatted. */ 00075 #define DELTA ((MSP430_CPU_SPEED) / (32768 / 8)) 00076 00077 unsigned int compare, oldcapture = 0; 00078 unsigned int i; 00079 00080 BCSCTL1 = 0xa4; /* ACLK is devided by 4. RSEL=6 no division for MCLK 00081 and SSMCLK. XT2 is off. */ 00082 00083 BCSCTL2 = 0x00; /* Init FLL to desired frequency using the 32762Hz 00084 crystal DCO frquenzy = 2,4576 MHz */ 00085 00086 BCSCTL1 |= DIVA1 + DIVA0; /* ACLK = LFXT1CLK/8 */ 00087 for(i = 0xffff; i > 0; i--) { /* Delay for XTAL to settle */ 00088 asm("nop"); 00089 } 00090 00091 CCTL2 = CCIS0 + CM0 + CAP; /* Define CCR2, CAP, ACLK */ 00092 TACTL = TASSEL1 + TACLR + MC1; /* SMCLK, continous mode */ 00093 00094 00095 while(1) { 00096 00097 while((CCTL2 & CCIFG) != CCIFG); /* Wait until capture occured! */ 00098 CCTL2 &= ~CCIFG; /* Capture occured, clear flag */ 00099 compare = CCR2; /* Get current captured SMCLK */ 00100 compare = compare - oldcapture; /* SMCLK difference */ 00101 oldcapture = CCR2; /* Save current captured SMCLK */ 00102 00103 if(DELTA == compare) { 00104 break; /* if equal, leave "while(1)" */ 00105 } else if(DELTA < compare) { /* DCO is too fast, slow it down */ 00106 DCOCTL--; 00107 if(DCOCTL == 0xFF) { /* Did DCO role under? */ 00108 BCSCTL1--; 00109 } 00110 } else { /* -> Select next lower RSEL */ 00111 DCOCTL++; 00112 if(DCOCTL == 0x00) { /* Did DCO role over? */ 00113 BCSCTL1++; 00114 } 00115 /* -> Select next higher RSEL */ 00116 } 00117 } 00118 00119 CCTL2 = 0; /* Stop CCR2 function */ 00120 TACTL = 0; /* Stop Timer_A */ 00121 00122 BCSCTL1 &= ~(DIVA1 + DIVA0); /* remove /8 divisor from ACLK again */ 00123 } 00124 /*---------------------------------------------------------------------------*/ 00125 static void 00126 init_ports(void) 00127 { 00128 /* Turn everything off, device drivers enable what is needed. */ 00129 00130 /* All configured for digital I/O */ 00131 #ifdef P1SEL 00132 P1SEL = 0; 00133 #endif 00134 #ifdef P2SEL 00135 P2SEL = 0; 00136 #endif 00137 #ifdef P3SEL 00138 P3SEL = 0; 00139 #endif 00140 #ifdef P4SEL 00141 P4SEL = 0; 00142 #endif 00143 #ifdef P5SEL 00144 P5SEL = 0; 00145 #endif 00146 #ifdef P6SEL 00147 P6SEL = 0; 00148 #endif 00149 00150 /* All available inputs */ 00151 #ifdef P1DIR 00152 P1DIR = 0; 00153 P1OUT = 0; 00154 #endif 00155 #ifdef P2DIR 00156 P2DIR = 0; 00157 P2OUT = 0; 00158 #endif 00159 #ifdef P3DIR 00160 P3DIR = 0; 00161 P3OUT = 0; 00162 #endif 00163 #ifdef P4DIR 00164 P4DIR = 0; 00165 P4OUT = 0; 00166 #endif 00167 00168 #ifdef P5DIR 00169 P5DIR = 0; 00170 P5OUT = 0; 00171 #endif 00172 00173 #ifdef P6DIR 00174 P6DIR = 0; 00175 P6OUT = 0; 00176 #endif 00177 00178 #ifdef P7DIR 00179 P7DIR = 0; 00180 P7OUT = 0; 00181 #endif 00182 00183 #ifdef P8DIR 00184 P8DIR = 0; 00185 P8OUT = 0; 00186 #endif 00187 00188 P1IE = 0; 00189 P2IE = 0; 00190 } 00191 /*---------------------------------------------------------------------------*/ 00192 /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */ 00193 #if defined(__MSP430__) && defined(__GNUC__) 00194 extern int _end; /* Not in sys/unistd.h */ 00195 static char *cur_break = (char *)&_end; 00196 #endif 00197 00198 /*---------------------------------------------------------------------------*/ 00199 /* add/remove_lpm_req - for requiring a specific LPM mode. currently Contiki */ 00200 /* jumps to LPM3 to save power, but DMA will not work if DCO is not clocked */ 00201 /* so some modules might need to enter their LPM requirements */ 00202 /* NOTE: currently only works with LPM1 (e.g. DCO) requirements. */ 00203 /*---------------------------------------------------------------------------*/ 00204 void 00205 msp430_add_lpm_req(int req) 00206 { 00207 if(req <= MSP430_REQUIRE_LPM1) { 00208 msp430_dco_required++; 00209 } 00210 } 00211 00212 void 00213 msp430_remove_lpm_req(int req) 00214 { 00215 if(req <= MSP430_REQUIRE_LPM1) { 00216 msp430_dco_required--; 00217 } 00218 } 00219 00220 void 00221 msp430_cpu_init(void) 00222 { 00223 dint(); 00224 watchdog_init(); 00225 init_ports(); 00226 msp430_init_dco(); 00227 eint(); 00228 #if defined(__MSP430__) && defined(__GNUC__) 00229 if((uintptr_t)cur_break & 1) { /* Workaround for msp430-ld bug! */ 00230 cur_break++; 00231 } 00232 #endif 00233 00234 msp430_dco_required = 0; 00235 } 00236 /*---------------------------------------------------------------------------*/ 00237 00238 #define STACK_EXTRA 32 00239 00240 /* 00241 * Allocate memory from the heap. Check that we don't collide with the 00242 * stack right now (some other routine might later). A watchdog might 00243 * be used to check if cur_break and the stack pointer meet during 00244 * runtime. 00245 */ 00246 #if defined(__MSP430__) && defined(__GNUC__) 00247 void * 00248 sbrk(int incr) 00249 { 00250 char *stack_pointer; 00251 00252 asmv("mov r1, %0" : "=r" (stack_pointer)); 00253 stack_pointer -= STACK_EXTRA; 00254 if(incr > (stack_pointer - cur_break)) 00255 return (void *)-1; /* ENOMEM */ 00256 00257 void *old_break = cur_break; 00258 cur_break += incr; 00259 /* 00260 * If the stack was never here then [old_break .. cur_break] should 00261 * be filled with zeros. 00262 */ 00263 return old_break; 00264 } 00265 #endif 00266 /*---------------------------------------------------------------------------*/ 00267 /* 00268 * Mask all interrupts that can be masked. 00269 */ 00270 int 00271 splhigh_(void) 00272 { 00273 int sr; 00274 /* Clear the GIE (General Interrupt Enable) flag. */ 00275 #ifdef __IAR_SYSTEMS_ICC__ 00276 sr = __get_SR_register(); 00277 __bic_SR_register(GIE); 00278 #else 00279 asmv("mov r2, %0" : "=r" (sr)); 00280 asmv("bic %0, r2" : : "i" (GIE)); 00281 #endif 00282 return sr & GIE; /* Ignore other sr bits. */ 00283 } 00284 /*---------------------------------------------------------------------------*/ 00285 /* 00286 * Restore previous interrupt mask. 00287 */ 00288 /* void */ 00289 /* splx_(int sr) */ 00290 /* { */ 00291 /* #ifdef __IAR_SYSTEMS_ICC__ */ 00292 /* __bis_SR_register(sr); */ 00293 /* #else */ 00294 /* /\* If GIE was set, restore it. *\/ */ 00295 /* asmv("bis %0, r2" : : "r" (sr)); */ 00296 /* #endif */ 00297 /* } */ 00298 /*---------------------------------------------------------------------------*/ 00299 #ifdef __IAR_SYSTEMS_ICC__ 00300 int __low_level_init(void) 00301 { 00302 /* turn off watchdog so that C-init will run */ 00303 WDTCTL = WDTPW + WDTHOLD; 00304 /* 00305 * Return value: 00306 * 00307 * 1 - Perform data segment initialization. 00308 * 0 - Skip data segment initialization. 00309 */ 00310 return 1; 00311 } 00312 #endif 00313 /*---------------------------------------------------------------------------*/ 00314 #if DCOSYNCH_CONF_ENABLED 00315 /* this code will always start the TimerB if not already started */ 00316 void 00317 msp430_sync_dco(void) { 00318 uint16_t last; 00319 uint16_t diff; 00320 /* uint32_t speed; */ 00321 /* DELTA_2 assumes an ACLK of 32768 Hz */ 00322 #define DELTA_2 ((MSP430_CPU_SPEED) / 32768) 00323 00324 /* Select SMCLK clock, and capture on ACLK for TBCCR6 */ 00325 TBCTL = TBSSEL1 | TBCLR; 00326 TBCCTL6 = CCIS0 + CM0 + CAP; 00327 /* start the timer */ 00328 TBCTL |= MC1; 00329 00330 /* wait for next Capture */ 00331 TBCCTL6 &= ~CCIFG; 00332 while(!(TBCCTL6 & CCIFG)); 00333 last = TBCCR6; 00334 00335 TBCCTL6 &= ~CCIFG; 00336 /* wait for next Capture - and calculate difference */ 00337 while(!(TBCCTL6 & CCIFG)); 00338 diff = TBCCR6 - last; 00339 00340 /* Stop timer - conserves energy according to user guide */ 00341 TBCTL = 0; 00342 00343 /* speed = diff; */ 00344 /* speed = speed * 32768; */ 00345 /* printf("Last TAR diff:%d target: %ld ", diff, DELTA_2); */ 00346 /* printf("CPU Speed: %lu DCOCTL: %d\n", speed, DCOCTL); */ 00347 00348 /* resynchronize the DCO speed if not at target */ 00349 if(DELTA_2 < diff) { /* DCO is too fast, slow it down */ 00350 DCOCTL--; 00351 if(DCOCTL == 0xFF) { /* Did DCO role under? */ 00352 BCSCTL1--; 00353 } 00354 } else if(DELTA_2 > diff) { 00355 DCOCTL++; 00356 if(DCOCTL == 0x00) { /* Did DCO role over? */ 00357 BCSCTL1++; 00358 } 00359 } 00360 } 00361 #endif /* DCOSYNCH_CONF_ENABLED */ 00362 /*---------------------------------------------------------------------------*/