Contiki-NG
msp430.c
1 /*
2  * Copyright (c) 2011, 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 #include "contiki.h"
32 #include "dev/watchdog.h"
33 
34 /* dco_required set to 1 will cause the CPU not to go into
35  sleep modes where the DCO clock stopped */
36 int msp430_dco_required;
37 
38 #if defined(__MSP430__) && defined(__GNUC__)
39 #define asmv(arg) __asm__ __volatile__(arg)
40 #endif
41 /*---------------------------------------------------------------------------*/
42 void
43 msp430_init_dco(void)
44 {
45 #ifdef __IAR_SYSTEMS_ICC__
46  __bis_SR_register(SCG0);
47 #else
48  asmv("bis %0, r2" : : "i" (SCG0));
49 #endif
50 
51  UCSCTL0 = 0x0000;
52  UCSCTL1 = DCORSEL_4;
53 
54  UCSCTL2 = MSP430_CPU_SPEED / 32768;
55  UCSCTL4 = 0x33; /* instead of 0x44 that is DCO/2 */
56 
57 #ifdef __IAR_SYSTEMS_ICC__
58  __bic_SR_register(SCG0);
59 #else
60  asmv("bic %0, r2" : : "i" (SCG0));
61 #endif
62 }
63 /*---------------------------------------------------------------------------*/
64 
65 static void
66 init_ports(void)
67 {
68  /* Turn everything off, device drivers enable what is needed. */
69  /* All configured for digital I/O */
70 #ifdef P1SEL
71  P1SEL = 0;
72 #endif
73 #ifdef P2SEL
74  P2SEL = 0;
75 #endif
76 #ifdef P3SEL
77  P3SEL = 0;
78 #endif
79 #ifdef P4SEL
80  P4SEL = 0;
81 #endif
82 #ifdef P5SEL
83  P5SEL = 0;
84 #endif
85 #ifdef P6SEL
86  P6SEL = 0;
87 #endif
88 
89  /* All available inputs */
90 #ifdef P1DIR
91  P1DIR = 0;
92  P1OUT = 0;
93 #endif
94 #ifdef P2DIR
95  P2DIR = 0;
96  P2OUT = 0;
97 #endif
98 #ifdef P3DIR
99  P3DIR = 0;
100  P3OUT = 0;
101 #endif
102 #ifdef P4DIR
103  P4DIR = 0;
104  P4OUT = 0;
105 #endif
106 
107 #ifdef P5DIR
108  P5DIR = 0;
109  P5OUT = 0;
110 #endif
111 
112 #ifdef P6DIR
113  P6DIR = 0;
114  P6OUT = 0;
115 #endif
116 
117 #ifdef P7DIR
118  P7DIR = 0;
119  P7OUT = 0;
120 #endif
121 
122 #ifdef P8DIR
123  P8DIR = 0;
124  P8OUT = 0;
125 #endif
126 
127  P1IE = 0;
128  P2IE = 0;
129 }
130 /*---------------------------------------------------------------------------*/
131 /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */
132 #if defined(__MSP430__) && defined(__GNUC__)
133 extern int _end; /* Not in sys/unistd.h */
134 static char *cur_break = (char *)&_end;
135 #endif
136 
137 /*---------------------------------------------------------------------------*/
138 /* add/remove_lpm_req - for requiring a specific LPM mode. currently Contiki */
139 /* jumps to LPM3 to save power, but DMA will not work if DCO is not clocked */
140 /* so some modules might need to enter their LPM requirements */
141 /* NOTE: currently only works with LPM1 (e.g. DCO) requirements. */
142 /*---------------------------------------------------------------------------*/
143 void
144 msp430_add_lpm_req(int req)
145 {
146  if(req <= MSP430_REQUIRE_LPM1) {
147  msp430_dco_required++;
148  }
149 }
150 
151 void
152 msp430_remove_lpm_req(int req)
153 {
154  if(req <= MSP430_REQUIRE_LPM1) {
155  msp430_dco_required--;
156  }
157 }
158 
159 void
160 msp430_cpu_init(void)
161 {
162  dint();
163  watchdog_init();
164  init_ports();
165  msp430_init_dco();
166  eint();
167 #if defined(__MSP430__) && defined(__GNUC__)
168  if((uintptr_t)cur_break & 1) { /* Workaround for msp430-ld bug! */
169  cur_break++;
170  }
171 #endif
172 
173  msp430_dco_required = 0;
174 }
175 /*---------------------------------------------------------------------------*/
176 
177 #define STACK_EXTRA 32
178 
179 /*
180  * Allocate memory from the heap. Check that we don't collide with the
181  * stack right now (some other routine might later). A watchdog might
182  * be used to check if cur_break and the stack pointer meet during
183  * runtime.
184  */
185 #if defined(__MSP430__) && defined(__GNUC__)
186 void *
187 sbrk(int incr)
188 {
189  char *stack_pointer;
190 
191  asmv("mov r1, %0" : "=r" (stack_pointer));
192  stack_pointer -= STACK_EXTRA;
193  if(incr > (stack_pointer - cur_break))
194  return (void *)-1; /* ENOMEM */
195 
196  void *old_break = cur_break;
197  cur_break += incr;
198  /*
199  * If the stack was never here then [old_break .. cur_break] should
200  * be filled with zeros.
201  */
202  return old_break;
203 }
204 #endif
205 /*---------------------------------------------------------------------------*/
206 /*
207  * Mask all interrupts that can be masked.
208  */
209 int
210 splhigh_(void)
211 {
212  int sr;
213  /* Clear the GIE (General Interrupt Enable) flag. */
214 #ifdef __IAR_SYSTEMS_ICC__
215  sr = __get_SR_register();
216  __bic_SR_register(GIE);
217 #else
218  asmv("mov r2, %0" : "=r" (sr));
219  asmv("bic %0, r2" : : "i" (GIE));
220 #endif
221  return sr & GIE; /* Ignore other sr bits. */
222 }
223 /*---------------------------------------------------------------------------*/
224 #ifdef __IAR_SYSTEMS_ICC__
225 int __low_level_init(void)
226 {
227  /* turn off watchdog so that C-init will run */
228  WDTCTL = WDTPW + WDTHOLD;
229  /*
230  * Return value:
231  *
232  * 1 - Perform data segment initialization.
233  * 0 - Skip data segment initialization.
234  */
235  return 1;
236 }
237 #endif
238 /*---------------------------------------------------------------------------*/
void watchdog_init(void)
Initialisation function for the WDT.
Definition: watchdog.c:63