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 #if defined(__MSP430__) && defined(__GNUC__) 00036 #define asmv(arg) __asm__ __volatile__(arg) 00037 #endif 00038 00039 /*---------------------------------------------------------------------------*/ 00040 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND 00041 void * 00042 w_memcpy(void *out, const void *in, size_t n) 00043 { 00044 uint8_t *src, *dest; 00045 src = (uint8_t *) in; 00046 dest = (uint8_t *) out; 00047 while(n-- > 0) { 00048 *dest++ = *src++; 00049 } 00050 return out; 00051 } 00052 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */ 00053 /*---------------------------------------------------------------------------*/ 00054 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND 00055 void * 00056 w_memset(void *out, int value, size_t n) 00057 { 00058 uint8_t *dest; 00059 dest = (uint8_t *) out; 00060 while(n-- > 0) { 00061 *dest++ = value & 0xff; 00062 } 00063 return out; 00064 } 00065 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */ 00066 /*---------------------------------------------------------------------------*/ 00067 void 00068 msp430_init_dco(void) 00069 { 00070 if(CALBC1_8MHZ != 0xFF) { 00071 DCOCTL = 0x00; 00072 BCSCTL1 = CALBC1_8MHZ; /*Set DCO to 8MHz */ 00073 DCOCTL = CALDCO_8MHZ; 00074 } else { /*start using reasonable values at 8 Mhz */ 00075 DCOCTL = 0x00; 00076 BCSCTL1 = 0x8D; 00077 DCOCTL = 0x88; 00078 } 00079 00080 /*BCSCTL1 |= XT2OFF; // Make sure XT2 is off */ 00081 /* BCSCTL2 = 0x00; // MCLK = DCOCLK/1 */ 00082 /* SMCLK = DCOCLK/1 */ 00083 /* DCO Internal Resistor */ 00084 } 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 static void 00149 init_ports(void) 00150 { 00151 /* Turn everything off, device drivers enable what is needed. */ 00152 00153 /* All configured for digital I/O */ 00154 #ifdef P1SEL 00155 P1SEL = 0; 00156 #endif 00157 #ifdef P2SEL 00158 P2SEL = 0; 00159 #endif 00160 #ifdef P3SEL 00161 P3SEL = 0; 00162 #endif 00163 #ifdef P4SEL 00164 P4SEL = 0; 00165 #endif 00166 #ifdef P5SEL 00167 P5SEL = 0; 00168 #endif 00169 #ifdef P6SEL 00170 P6SEL = 0; 00171 #endif 00172 00173 /* All available inputs */ 00174 #ifdef P1DIR 00175 P1DIR = 0; 00176 P1OUT = 0; 00177 #endif 00178 #ifdef P2DIR 00179 P2DIR = 0; 00180 P2OUT = 0; 00181 #endif 00182 #ifdef P3DIR 00183 P3DIR = 0; 00184 P3OUT = 0; 00185 #endif 00186 #ifdef P4DIR 00187 P4DIR = 0; 00188 P4OUT = 0; 00189 #endif 00190 00191 #ifdef P5DIR 00192 P5DIR = 0; 00193 P5OUT = 0; 00194 #endif 00195 00196 #ifdef P6DIR 00197 P6DIR = 0; 00198 P6OUT = 0; 00199 #endif 00200 00201 #ifdef P7DIR 00202 P7DIR = 0; 00203 P7OUT = 0; 00204 #endif 00205 00206 #ifdef P8DIR 00207 P8DIR = 0; 00208 P8OUT = 0; 00209 #endif 00210 00211 P1IE = 0; 00212 P2IE = 0; 00213 } 00214 /*---------------------------------------------------------------------------*/ 00215 /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */ 00216 #if defined(__MSP430__) && defined(__GNUC__) 00217 extern int _end; /* Not in sys/unistd.h */ 00218 static char *cur_break = (char *)&_end; 00219 #endif 00220 00221 void 00222 msp430_cpu_init(void) 00223 { 00224 dint(); 00225 watchdog_init(); 00226 init_ports(); 00227 msp430_quick_synch_dco(); 00228 eint(); 00229 #if defined(__MSP430__) && defined(__GNUC__) 00230 if((uintptr_t)cur_break & 1) { /* Workaround for msp430-ld bug! */ 00231 cur_break++; 00232 } 00233 #endif 00234 } 00235 /*---------------------------------------------------------------------------*/ 00236 00237 /*---------------------------------------------------------------------------*/ 00238 /* 00239 * Mask all interrupts that can be masked. 00240 */ 00241 int 00242 splhigh_(void) 00243 { 00244 /* Clear the GIE (General Interrupt Enable) flag. */ 00245 int sr; 00246 #ifdef __IAR_SYSTEMS_ICC__ 00247 sr = __get_SR_register(); 00248 __bic_SR_register(GIE); 00249 #else 00250 asmv("mov r2, %0" : "=r" (sr)); 00251 asmv("bic %0, r2" : : "i" (GIE)); 00252 #endif 00253 return sr & GIE; /* Ignore other sr bits. */ 00254 } 00255 /*---------------------------------------------------------------------------*/ 00256 /* 00257 * Restore previous interrupt mask. 00258 */ 00259 /* void */ 00260 /* splx_(int sr) */ 00261 /* { */ 00262 /* #ifdef __IAR_SYSTEMS_ICC__ */ 00263 /* __bis_SR_register(sr); */ 00264 /* #else */ 00265 /* /\* If GIE was set, restore it. *\/ */ 00266 /* asmv("bis %0, r2" : : "r" (sr)); */ 00267 /* #endif */ 00268 /* } */ 00269 /*---------------------------------------------------------------------------*/ 00270 #ifdef __IAR_SYSTEMS_ICC__ 00271 int __low_level_init(void) 00272 { 00273 /* turn off watchdog so that C-init will run */ 00274 WDTCTL = WDTPW + WDTHOLD; 00275 /* 00276 * Return value: 00277 * 00278 * 1 - Perform data segment initialization. 00279 * 0 - Skip data segment initialization. 00280 */ 00281 return 1; 00282 } 00283 #endif 00284 /*---------------------------------------------------------------------------*/ 00285 #if DCOSYNCH_CONF_ENABLED 00286 /* this code will always start the TimerB if not already started */ 00287 void 00288 msp430_sync_dco(void) { 00289 uint16_t last; 00290 uint16_t diff; 00291 /* uint32_t speed; */ 00292 /* DELTA_2 assumes an ACLK of 32768 Hz */ 00293 #define DELTA_2 ((MSP430_CPU_SPEED) / 32768) 00294 00295 /* Select SMCLK clock, and capture on ACLK for TBCCR6 */ 00296 TBCTL = TBSSEL1 | TBCLR; 00297 TBCCTL6 = CCIS0 + CM0 + CAP; 00298 /* start the timer */ 00299 TBCTL |= MC1; 00300 00301 /* wait for next Capture */ 00302 TBCCTL6 &= ~CCIFG; 00303 while(!(TBCCTL6 & CCIFG)); 00304 last = TBCCR6; 00305 00306 TBCCTL6 &= ~CCIFG; 00307 /* wait for next Capture - and calculate difference */ 00308 while(!(TBCCTL6 & CCIFG)); 00309 diff = TBCCR6 - last; 00310 00311 /* Stop timer - conserves energy according to user guide */ 00312 TBCTL = 0; 00313 00314 /* speed = diff; */ 00315 /* speed = speed * 32768; */ 00316 /* printf("Last TAR diff:%d target: %ld ", diff, DELTA_2); */ 00317 /* printf("CPU Speed: %lu DCOCTL: %d\n", speed, DCOCTL); */ 00318 00319 /* resynchronize the DCO speed if not at target */ 00320 if(DELTA_2 < diff) { /* DCO is too fast, slow it down */ 00321 DCOCTL--; 00322 if(DCOCTL == 0xFF) { /* Did DCO role under? */ 00323 BCSCTL1--; 00324 } 00325 } else if(DELTA_2 > diff) { 00326 DCOCTL++; 00327 if(DCOCTL == 0x00) { /* Did DCO role over? */ 00328 BCSCTL1++; 00329 } 00330 } 00331 } 00332 #endif /* DCOSYNCH_CONF_ENABLED */ 00333 /*---------------------------------------------------------------------------*/