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