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  * @(#)$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 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:39 2011 for Contiki 2.5 by  doxygen 1.6.1