Contiki 2.5
msp430.c
1 /*
2  * Copyright (c) 2005, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * @(#)$Id: msp430.c,v 1.1 2010/08/24 16:26:38 joxe Exp $
32  */
33 
34 #include "contiki.h"
35 
36 #ifdef __IAR_SYSTEMS_ICC__
37 #include <msp430.h>
38 #else
39 #include <io.h>
40 #include <signal.h>
41 #include <sys/unistd.h>
42 #define asmv(arg) __asm__ __volatile__(arg)
43 #endif
44 
45 #include "msp430def.h"
46 #include "dev/watchdog.h"
47 #include "net/uip.h"
48 
49 /*---------------------------------------------------------------------------*/
50 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND
51 void *
52 w_memcpy(void *out, const void *in, size_t n)
53 {
54  uint8_t *src, *dest;
55  src = (uint8_t *) in;
56  dest = (uint8_t *) out;
57  while(n-- > 0) {
58  *dest++ = *src++;
59  }
60  return out;
61 }
62 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */
63 /*---------------------------------------------------------------------------*/
64 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND
65 void *
66 w_memset(void *out, int value, size_t n)
67 {
68  uint8_t *dest;
69  dest = (uint8_t *) out;
70  while(n-- > 0) {
71  *dest++ = value & 0xff;
72  }
73  return out;
74 }
75 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */
76 /*---------------------------------------------------------------------------*/
77 void
78 msp430_init_dco(void)
79 {
80  if(CALBC1_8MHZ != 0xFF) {
81  DCOCTL = 0x00;
82  BCSCTL1 = CALBC1_8MHZ; /*Set DCO to 8MHz */
83  DCOCTL = CALDCO_8MHZ;
84  } else { /*start using reasonable values at 8 Mhz */
85  DCOCTL = 0x00;
86  BCSCTL1 = 0x8D;
87  DCOCTL = 0x88;
88  }
89 
90  /*BCSCTL1 |= XT2OFF; // Make sure XT2 is off */
91  /* BCSCTL2 = 0x00; // MCLK = DCOCLK/1 */
92  /* SMCLK = DCOCLK/1 */
93  /* DCO Internal Resistor */
94 }
95 /*---------------------------------------------------------------------------*/
96 /*---------------------------------------------------------------------------*/
97 /* Start CPU with full speed (? good or bad?) and go downwards */
98 /*---------------------------------------------------------------------------*/
99 void
100 msp430_quick_synch_dco(void) {
101  uint16_t last;
102  uint16_t diff;
103  uint16_t dco_reg = 0x0fff;
104  uint8_t current_bit = 12;
105  uint16_t i;
106  /* DELTA_2 assumes an ACLK of 32768 Hz */
107 #define DELTA_2 ((MSP430_CPU_SPEED) / 32768)
108 
109  /* Select SMCLK clock, and capture on ACLK for TBCCR6 */
110  TBCTL = TBSSEL1 | TBCLR;
111  TBCCTL6 = CCIS0 + CM0 + CAP;
112  /* start the timer */
113  TBCTL |= MC1;
114 
115  BCSCTL1 = 0x8D | 7;
116  DCOCTL = 0xff; /* MAX SPEED ?? */
117 
118  /* IDEA: do binary search - check MSB first, etc... */
119  /* 1 set current bit to zero - if to slow, put back to 1 */
120  while(current_bit--) {
121  /* first set the current bit to zero and check - we know that it is
122  set from start so ^ works (first bit = bit 11) */
123  dco_reg = dco_reg ^ (1 << current_bit); /* clear bit 11..10..9.. */
124 
125  /* set dco registers */
126  DCOCTL = dco_reg & 0xff;
127  BCSCTL1 = (BCSCTL1 & 0xf8) | (dco_reg >> 8);
128 
129  /* some delay to make clock stable - could possibly be made using
130  captures too ... */
131  for(i=0; i < 1000; i++) {
132  i = i | 1;
133  }
134 
135 
136  /* do capture... */
137  while(!(TBCCTL6 & CCIFG));
138  last = TBCCR6;
139 
140  TBCCTL6 &= ~CCIFG;
141  /* wait for next Capture - and calculate difference */
142  while(!(TBCCTL6 & CCIFG));
143  diff = TBCCR6 - last;
144 
145 /* /\* store what was run during the specific test *\/ */
146 /* dcos[current_bit] = dco_reg; */
147 /* vals[current_bit] = diff; */
148 
149  /* should we keep the bit cleared or not ? */
150  if (diff < DELTA_2) { /* DCO is too slow - fewer ticks than desired */
151  /* toggle bit again to get it back to one */
152  dco_reg = dco_reg ^ (1 << current_bit);
153  }
154  }
155 }
156 /*---------------------------------------------------------------------------*/
157 void
158 msp430_init_dco_old(void) /*Enric NOT IN USE, RIGHT NOW */
159 {
160  /* This code taken from the FU Berlin sources and reformatted. */
161 #define DELTA ((MSP430_CPU_SPEED) / (32768 / 8))
162 
163  unsigned int compare, oldcapture = 0;
164  unsigned int i;
165 
166 
167  BCSCTL1 = 0xa4; /* ACLK is devided by 4. RSEL=6 no division for MCLK
168  and SSMCLK. XT2 is off. */
169 
170  BCSCTL2 = 0x00; /* Init FLL to desired frequency using the 32762Hz
171  crystal DCO frquenzy = 2,4576 MHz */
172 
173  BCSCTL1 |= DIVA1 + DIVA0; /* ACLK = LFXT1CLK/8 */
174  for(i = 0xffff; i > 0; i--) { /* Delay for XTAL to settle */
175  asm("nop");
176  }
177 
178  CCTL2 = CCIS0 + CM0 + CAP; /* Define CCR2, CAP, ACLK */
179  TACTL = TASSEL1 + TACLR + MC1; // SMCLK, continous mode
180 
181 
182  while(1) {
183 
184  while((CCTL2 & CCIFG) != CCIFG); /* Wait until capture occured! */
185  CCTL2 &= ~CCIFG; /* Capture occured, clear flag */
186  compare = CCR2; /* Get current captured SMCLK */
187  compare = compare - oldcapture; /* SMCLK difference */
188  oldcapture = CCR2; /* Save current captured SMCLK */
189 
190  if(DELTA == compare) {
191  break; /* if equal, leave "while(1)" */
192  } else if(DELTA < compare) { /* DCO is too fast, slow it down */
193  DCOCTL--;
194  if(DCOCTL == 0xFF) { /* Did DCO role under? */
195  BCSCTL1--;
196  }
197  } else { /* -> Select next lower RSEL */
198  DCOCTL++;
199  if(DCOCTL == 0x00) { /* Did DCO role over? */
200  BCSCTL1++;
201  }
202  /* -> Select next higher RSEL */
203  }
204  }
205 
206  CCTL2 = 0; /* Stop CCR2 function */
207  TACTL = 0; /* Stop Timer_A */
208 
209  BCSCTL1 &= ~(DIVA1 + DIVA0); /* remove /8 divisor from ACLK again */
210 }
211 /*---------------------------------------------------------------------------*/
212 
213 static void
214 init_ports(void)
215 {
216  /* Turn everything off, device drivers enable what is needed. */
217 
218  /* All configured for digital I/O */
219 #ifdef P1SEL
220  P1SEL = 0;
221 #endif
222 #ifdef P2SEL
223  P2SEL = 0;
224 #endif
225 #ifdef P3SEL
226  P3SEL = 0;
227 #endif
228 #ifdef P4SEL
229  P4SEL = 0;
230 #endif
231 #ifdef P5SEL
232  P5SEL = 0;
233 #endif
234 #ifdef P6SEL
235  P6SEL = 0;
236 #endif
237 
238  /* All available inputs */
239 #ifdef P1DIR
240  P1DIR = 0;
241  P1OUT = 0;
242 #endif
243 #ifdef P2DIR
244  P2DIR = 0;
245  P2OUT = 0;
246 #endif
247 #ifdef P3DIR
248  P3DIR = 0;
249  P3OUT = 0;
250 #endif
251 #ifdef P4DIR
252  P4DIR = 0;
253  P4OUT = 0;
254 #endif
255 
256 #ifdef P5DIR
257  P5DIR = 0;
258  P5OUT = 0;
259 #endif
260 
261 #ifdef P6DIR
262  P6DIR = 0;
263  P6OUT = 0;
264 #endif
265 
266  P1IE = 0;
267  P2IE = 0;
268 }
269 /*---------------------------------------------------------------------------*/
270 /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */
271 #ifdef __GNUC__
272 extern int _end; /* Not in sys/unistd.h */
273 static char *cur_break = (char *)&_end;
274 #endif
275 
276 void
277 msp430_cpu_init(void)
278 {
279  dint();
280  watchdog_init();
281  init_ports();
282  msp430_quick_synch_dco();
283  eint();
284 #ifdef __GNUC__
285  if((uintptr_t)cur_break & 1) { /* Workaround for msp430-ld bug! */
286  cur_break++;
287  }
288 #endif
289 }
290 /*---------------------------------------------------------------------------*/
291 
292 #define STACK_EXTRA 32
293 
294 /*---------------------------------------------------------------------------*/
295 /*
296  * Mask all interrupts that can be masked.
297  */
298 int
299 splhigh_(void)
300 {
301  /* Clear the GIE (General Interrupt Enable) flag. */
302  int sr;
303 #ifdef __IAR_SYSTEMS_ICC__
304  sr = __get_SR_register();
305  __bic_SR_register(GIE);
306 #else
307  asmv("mov r2, %0" : "=r" (sr));
308  asmv("bic %0, r2" : : "i" (GIE));
309 #endif
310  return sr & GIE; /* Ignore other sr bits. */
311 }
312 /*---------------------------------------------------------------------------*/
313 /*
314  * Restore previous interrupt mask.
315  */
316 void
317 splx_(int sr)
318 {
319 #ifdef __IAR_SYSTEMS_ICC__
320  __bis_SR_register(sr);
321 #else
322  /* If GIE was set, restore it. */
323  asmv("bis %0, r2" : : "r" (sr));
324 #endif
325 }
326 /*---------------------------------------------------------------------------*/
327 /* this code will always start the TimerB if not already started */
328 void
329 msp430_sync_dco(void) {
330  uint16_t last;
331  uint16_t diff;
332 /* uint32_t speed; */
333  /* DELTA_2 assumes an ACLK of 32768 Hz */
334 #define DELTA_2 ((MSP430_CPU_SPEED) / 32768)
335 
336  /* Select SMCLK clock, and capture on ACLK for TBCCR6 */
337  TBCTL = TBSSEL1 | TBCLR;
338  TBCCTL6 = CCIS0 + CM0 + CAP;
339  /* start the timer */
340  TBCTL |= MC1;
341 
342  /* wait for next Capture */
343  TBCCTL6 &= ~CCIFG;
344  while(!(TBCCTL6 & CCIFG));
345  last = TBCCR6;
346 
347  TBCCTL6 &= ~CCIFG;
348  /* wait for next Capture - and calculate difference */
349  while(!(TBCCTL6 & CCIFG));
350  diff = TBCCR6 - last;
351 
352  /* Stop timer - conserves energy according to user guide */
353  TBCTL = 0;
354 
355  /* speed = diff; */
356  /* speed = speed * 32768; */
357  /* printf("Last TAR diff:%d target: %ld ", diff, DELTA_2); */
358  /* printf("CPU Speed: %lu DCOCTL: %d\n", speed, DCOCTL); */
359 
360  /* resynchronize the DCO speed if not at target */
361  if(DELTA_2 < diff) { /* DCO is too fast, slow it down */
362  DCOCTL--;
363  if(DCOCTL == 0xFF) { /* Did DCO role under? */
364  BCSCTL1--;
365  }
366  } else if (DELTA_2 > diff) {
367  DCOCTL++;
368  if(DCOCTL == 0x00) { /* Did DCO role over? */
369  BCSCTL1++;
370  }
371  }
372 }
373 /*---------------------------------------------------------------------------*/