Contiki-NG
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 
32 #include "contiki.h"
33 #include "dev/watchdog.h"
34 
35 /* dco_required set to 1 will cause the CPU not to go into
36  * sleep modes where the DCO clock stopped */
37 int msp430_dco_required;
38 
39 #if defined(__MSP430__) && defined(__GNUC__)
40 #define asmv(arg) __asm__ __volatile__ (arg)
41 #endif
42 
43 /*---------------------------------------------------------------------------*/
44 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND
45 void *
46 w_memcpy(void *out, const void *in, size_t n)
47 {
48  uint8_t *src, *dest;
49  src = (uint8_t *)in;
50  dest = (uint8_t *)out;
51  while(n-- > 0) {
52  *dest++ = *src++;
53  }
54  return out;
55 }
56 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */
57 /*---------------------------------------------------------------------------*/
58 #if defined(__MSP430__) && defined(__GNUC__) && MSP430_MEMCPY_WORKAROUND
59 void *
60 w_memset(void *out, int value, size_t n)
61 {
62  uint8_t *dest;
63  dest = (uint8_t *)out;
64  while(n-- > 0) {
65  *dest++ = value & 0xff;
66  }
67  return out;
68 }
69 #endif /* __GNUC__ && __MSP430__ && MSP430_MEMCPY_WORKAROUND */
70 /*---------------------------------------------------------------------------*/
71 void
72 msp430_init_dco(void)
73 {
74  if(CALBC1_8MHZ != 0xFF) {
75  DCOCTL = 0x00;
76  BCSCTL1 = CALBC1_8MHZ; /*Set DCO to 8MHz */
77  DCOCTL = CALDCO_8MHZ;
78  } else { /*start using reasonable values at 8 Mhz */
79  DCOCTL = 0x00;
80  BCSCTL1 = 0x8D;
81  DCOCTL = 0x88;
82  }
83 
84  /*BCSCTL1 |= XT2OFF; // Make sure XT2 is off */
85  /* BCSCTL2 = 0x00; // MCLK = DCOCLK/1 */
86  /* SMCLK = DCOCLK/1 */
87  /* DCO Internal Resistor */
88 }
89 /*---------------------------------------------------------------------------*/
90 static void
91 init_ports(void)
92 {
93  /* Turn everything off, device drivers enable what is needed. */
94 
95  /* All configured for digital I/O */
96 #ifdef P1SEL
97  P1SEL = 0;
98 #endif
99 #ifdef P2SEL
100  P2SEL = 0;
101 #endif
102 #ifdef P3SEL
103  P3SEL = 0;
104 #endif
105 #ifdef P4SEL
106  P4SEL = 0;
107 #endif
108 #ifdef P5SEL
109  P5SEL = 0;
110 #endif
111 #ifdef P6SEL
112  P6SEL = 0;
113 #endif
114 
115  /* All available inputs */
116 #ifdef P1DIR
117  P1DIR = 0;
118  P1OUT = 0;
119 #endif
120 #ifdef P2DIR
121  P2DIR = 0;
122  P2OUT = 0;
123 #endif
124 #ifdef P3DIR
125  P3DIR = 0;
126  P3OUT = 0;
127 #endif
128 #ifdef P4DIR
129  P4DIR = 0;
130  P4OUT = 0;
131 #endif
132 
133 #ifdef P5DIR
134  P5DIR = 0;
135  P5OUT = 0;
136 #endif
137 
138 #ifdef P6DIR
139  P6DIR = 0;
140  P6OUT = 0;
141 #endif
142 
143 #ifdef P7DIR
144  P7DIR = 0;
145  P7OUT = 0;
146 #endif
147 
148 #ifdef P8DIR
149  P8DIR = 0;
150  P8OUT = 0;
151 #endif
152 
153  P1IE = 0;
154  P2IE = 0;
155 }
156 /*---------------------------------------------------------------------------*/
157 /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */
158 #if defined(__MSP430__) && defined(__GNUC__)
159 extern int _end; /* Not in sys/unistd.h */
160 static char *cur_break = (char *)&_end;
161 #endif
162 
163 /*---------------------------------------------------------------------------*/
164 /* add/remove_lpm_req - for requiring a specific LPM mode. currently Contiki */
165 /* jumps to LPM3 to save power, but DMA will not work if DCO is not clocked */
166 /* so some modules might need to enter their LPM requirements */
167 /* NOTE: currently only works with LPM1 (e.g. DCO) requirements. */
168 /*---------------------------------------------------------------------------*/
169 void
170 msp430_add_lpm_req(int req)
171 {
172  if(req <= MSP430_REQUIRE_LPM1) {
173  msp430_dco_required++;
174  }
175 }
176 void
177 msp430_remove_lpm_req(int req)
178 {
179  if(req <= MSP430_REQUIRE_LPM1) {
180  msp430_dco_required--;
181  }
182 }
183 void
184 msp430_cpu_init(void)
185 {
186  dint();
187  watchdog_init();
188  init_ports();
189  /* set DCO to a reasonable default value (8MHz) */
190  msp430_init_dco();
191  /* calibrate the DCO step-by-step */
192  msp430_sync_dco();
193  eint();
194 #if defined(__MSP430__) && defined(__GNUC__)
195  if((uintptr_t)cur_break & 1) { /* Workaround for msp430-ld bug! */
196  cur_break++;
197  }
198 #endif
199  msp430_dco_required = 0;
200 }
201 /*---------------------------------------------------------------------------*/
202 
203 /*---------------------------------------------------------------------------*/
204 /*
205  * Mask all interrupts that can be masked.
206  */
207 int
208 splhigh_(void)
209 {
210  /* Clear the GIE (General Interrupt Enable) flag. */
211  int sr;
212 #ifdef __IAR_SYSTEMS_ICC__
213  sr = __get_SR_register();
214  __bic_SR_register(GIE);
215 #else
216  asmv("mov r2, %0" : "=r" (sr));
217  asmv("bic %0, r2" : : "i" (GIE));
218 #endif
219  return sr & GIE; /* Ignore other sr bits. */
220 }
221 /*---------------------------------------------------------------------------*/
222 /*
223  * Restore previous interrupt mask.
224  */
225 /* void */
226 /* splx_(int sr) */
227 /* { */
228 /* #ifdef __IAR_SYSTEMS_ICC__ */
229 /* __bis_SR_register(sr); */
230 /* #else */
231 /* /\* If GIE was set, restore it. *\/ */
232 /* asmv("bis %0, r2" : : "r" (sr)); */
233 /* #endif */
234 /* } */
235 /*---------------------------------------------------------------------------*/
236 #ifdef __IAR_SYSTEMS_ICC__
237 int
238 __low_level_init(void)
239 {
240  /* turn off watchdog so that C-init will run */
241  WDTCTL = WDTPW + WDTHOLD;
242  /*
243  * Return value:
244  *
245  * 1 - Perform data segment initialization.
246  * 0 - Skip data segment initialization.
247  */
248  return 1;
249 }
250 #endif
251 /*---------------------------------------------------------------------------*/
252 void
253 msp430_sync_dco(void)
254 {
255  uint16_t oldcapture;
256  int16_t diff;
257  /* DELTA_2 assumes an ACLK of 32768 Hz */
258 #define DELTA_2 ((MSP430_CPU_SPEED) / 32768)
259 
260  /* Select SMCLK clock, and capture on ACLK for TBCCR6 */
261  TBCTL = TBSSEL1 | TBCLR;
262  TBCCTL6 = CCIS0 + CM0 + CAP;
263  /* start the timer */
264  TBCTL |= MC1;
265 
266  while(1) {
267  /* wait for the next capture */
268  TBCCTL6 &= ~CCIFG;
269  while(!(TBCCTL6 & CCIFG));
270  oldcapture = TBCCR6;
271 
272  /* wait for the next capture - and calculate difference */
273  TBCCTL6 &= ~CCIFG;
274  while(!(TBCCTL6 & CCIFG));
275  diff = TBCCR6 - oldcapture;
276 
277  /* resynchronize the DCO speed if not at target */
278  if(DELTA_2 == diff) {
279  break; /* if equal, leave "while(1)" */
280  } else if(DELTA_2 < diff) { /* DCO is too fast, slow it down */
281  DCOCTL--;
282  if(DCOCTL == 0xFF) { /* Did DCO roll under? */
283  BCSCTL1--;
284  }
285  } else { /* -> Select next lower RSEL */
286  DCOCTL++;
287  if(DCOCTL == 0x00) { /* Did DCO roll over? */
288  BCSCTL1++;
289  }
290  /* -> Select next higher RSEL */
291  }
292  }
293 
294  /* Stop the timer - conserves energy according to user guide */
295  TBCTL = 0;
296 }
297 /*---------------------------------------------------------------------------*/
void watchdog_init(void)
Initialisation function for the WDT.
Definition: watchdog.c:63