Allow build with original radio driver using $make RF230BB=0
[contiki-2.x.git] / cpu / msp430 / msp430.c
blob22e859c400b9b1b0742fec6f783240a9ac33b0de
1 /*
2 * Copyright (c) 2005, Swedish Institute of Computer Science
3 * All rights reserved.
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.
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.
29 * This file is part of the Contiki operating system.
31 * @(#)$Id: msp430.c,v 1.10 2009/02/04 18:28:44 joxe Exp $
33 #include <io.h>
34 #include <signal.h>
35 #include <sys/unistd.h>
36 #include "msp430.h"
37 #include "dev/watchdog.h"
38 #include "net/uip.h"
41 /*---------------------------------------------------------------------------*/
42 void
43 msp430_init_dco(void)
45 /* This code taken from the FU Berlin sources and reformatted. */
46 #define DELTA ((MSP430_CPU_SPEED) / (32768 / 8))
48 unsigned int compare, oldcapture = 0;
49 unsigned int i;
52 BCSCTL1 = 0xa4; /* ACLK is devided by 4. RSEL=6 no division for MCLK
53 and SSMCLK. XT2 is off. */
55 BCSCTL2 = 0x00; /* Init FLL to desired frequency using the 32762Hz
56 crystal DCO frquenzy = 2,4576 MHz */
58 BCSCTL1 |= DIVA1 + DIVA0; /* ACLK = LFXT1CLK/8 */
59 for(i = 0xffff; i > 0; i--) { /* Delay for XTAL to settle */
60 asm("nop");
63 CCTL2 = CCIS0 + CM0 + CAP; // Define CCR2, CAP, ACLK
64 TACTL = TASSEL1 + TACLR + MC1; // SMCLK, continous mode
67 while(1) {
69 while((CCTL2 & CCIFG) != CCIFG); /* Wait until capture occured! */
70 CCTL2 &= ~CCIFG; /* Capture occured, clear flag */
71 compare = CCR2; /* Get current captured SMCLK */
72 compare = compare - oldcapture; /* SMCLK difference */
73 oldcapture = CCR2; /* Save current captured SMCLK */
75 if(DELTA == compare) {
76 break; /* if equal, leave "while(1)" */
77 } else if(DELTA < compare) { /* DCO is too fast, slow it down */
78 DCOCTL--;
79 if(DCOCTL == 0xFF) { /* Did DCO role under? */
80 BCSCTL1--;
82 } else { /* -> Select next lower RSEL */
83 DCOCTL++;
84 if(DCOCTL == 0x00) { /* Did DCO role over? */
85 BCSCTL1++;
87 /* -> Select next higher RSEL */
91 CCTL2 = 0; /* Stop CCR2 function */
92 TACTL = 0; /* Stop Timer_A */
94 BCSCTL1 &= ~(DIVA1 + DIVA0); /* remove /8 divisor from ACLK again */
96 /*---------------------------------------------------------------------------*/
98 static void
99 init_ports(void)
101 /* Turn everything off, device drivers enable what is needed. */
103 /* All configured for digital I/O */
104 #ifdef P1SEL
105 P1SEL = 0;
106 #endif
107 #ifdef P2SEL
108 P2SEL = 0;
109 #endif
110 #ifdef P3SEL
111 P3SEL = 0;
112 #endif
113 #ifdef P4SEL
114 P4SEL = 0;
115 #endif
116 #ifdef P5SEL
117 P5SEL = 0;
118 #endif
119 #ifdef P6SEL
120 P6SEL = 0;
121 #endif
123 /* All available inputs */
124 #ifdef P1DIR
125 P1DIR = 0;
126 P1OUT = 0;
127 #endif
128 #ifdef P2DIR
129 P2DIR = 0;
130 P2OUT = 0;
131 #endif
132 #ifdef P3DIR
133 P3DIR = 0;
134 P3OUT = 0;
135 #endif
136 #ifdef P4DIR
137 P4DIR = 0;
138 P4OUT = 0;
139 #endif
141 #ifdef P5DIR
142 P5DIR = 0;
143 P5OUT = 0;
144 #endif
146 #ifdef P6DIR
147 P6DIR = 0;
148 P6OUT = 0;
149 #endif
151 P1IE = 0;
152 P2IE = 0;
154 /*---------------------------------------------------------------------------*/
155 /* msp430-ld may align _end incorrectly. Workaround in cpu_init. */
156 extern int _end; /* Not in sys/unistd.h */
157 static char *cur_break = (char *)&_end;
159 void
160 msp430_cpu_init(void)
162 dint();
163 watchdog_init();
164 init_ports();
165 msp430_init_dco();
166 eint();
167 if((uintptr_t)cur_break & 1) { /* Workaround for msp430-ld bug! */
168 cur_break++;
171 /*---------------------------------------------------------------------------*/
172 #define asmv(arg) __asm__ __volatile__(arg)
174 #define STACK_EXTRA 32
177 * Allocate memory from the heap. Check that we don't collide with the
178 * stack right now (some other routine might later). A watchdog might
179 * be used to check if cur_break and the stack pointer meet during
180 * runtime.
182 void *
183 sbrk(int incr)
185 char *stack_pointer;
187 asmv("mov r1, %0" : "=r" (stack_pointer));
188 stack_pointer -= STACK_EXTRA;
189 if(incr > (stack_pointer - cur_break))
190 return (void *)-1; /* ENOMEM */
192 void *old_break = cur_break;
193 cur_break += incr;
195 * If the stack was never here then [old_break .. cur_break] should
196 * be filled with zeros.
198 return old_break;
200 /*---------------------------------------------------------------------------*/
202 * Mask all interrupts that can be masked.
205 splhigh_(void)
207 /* Clear the GIE (General Interrupt Enable) flag. */
208 int sr;
209 asmv("mov r2, %0" : "=r" (sr));
210 asmv("bic %0, r2" : : "i" (GIE));
211 return sr & GIE; /* Ignore other sr bits. */
213 /*---------------------------------------------------------------------------*/
215 * Restore previous interrupt mask.
217 void
218 splx_(int sr)
220 /* If GIE was set, restore it. */
221 asmv("bis %0, r2" : : "r" (sr));
223 /*---------------------------------------------------------------------------*/
224 /* this code will always start the TimerB if not already started */
225 void
226 msp430_sync_dco(void) {
227 uint16_t last;
228 uint16_t diff;
229 /* uint32_t speed; */
230 /* DELTA_2 assumes an ACLK of 32768 Hz */
231 #define DELTA_2 ((MSP430_CPU_SPEED) / 32768)
233 /* Select SMCLK clock, and capture on ACLK for TBCCR6 */
234 TBCTL = TBSSEL1 | TBCLR;
235 TBCCTL6 = CCIS0 + CM0 + CAP;
236 /* start the timer */
237 TBCTL |= MC1;
239 // wait for next Capture
240 TBCCTL6 &= ~CCIFG;
241 while(!(TBCCTL6 & CCIFG));
242 last = TBCCR6;
244 TBCCTL6 &= ~CCIFG;
245 // wait for next Capture - and calculate difference
246 while(!(TBCCTL6 & CCIFG));
247 diff = TBCCR6 - last;
249 /* Stop timer - conserves energy according to user guide */
250 TBCTL = 0;
252 /* speed = diff; */
253 /* speed = speed * 32768; */
254 /* printf("Last TAR diff:%d target: %ld ", diff, DELTA_2); */
255 /* printf("CPU Speed: %lu DCOCTL: %d\n", speed, DCOCTL); */
257 /* resynchronize the DCO speed if not at target */
258 if(DELTA_2 < diff) { /* DCO is too fast, slow it down */
259 DCOCTL--;
260 if(DCOCTL == 0xFF) { /* Did DCO role under? */
261 BCSCTL1--;
263 } else if (DELTA_2 > diff) {
264 DCOCTL++;
265 if(DCOCTL == 0x00) { /* Did DCO role over? */
266 BCSCTL1++;
270 /*---------------------------------------------------------------------------*/