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