Contiki 2.6

msp430.c

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 /*---------------------------------------------------------------------------*/