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

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