Contiki-NG
Toggle main menu visibility
Loading...
Searching...
No Matches
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
/* This code taken from the FU Berlin sources and reformatted. */
75
#define DELTA ((MSP430_CPU_SPEED) / (32768 / 8))
76
77
unsigned
int
compare, oldcapture = 0;
78
unsigned
int
i;
79
80
BCSCTL1 = 0xa4;
/* ACLK is devided by 4. RSEL=6 no division for MCLK
81
and SSMCLK. XT2 is off. */
82
83
BCSCTL2 = 0x00;
/* Init FLL to desired frequency using the 32762Hz
84
crystal DCO frquenzy = 2,4576 MHz */
85
86
BCSCTL1 |= DIVA1 + DIVA0;
/* ACLK = LFXT1CLK/8 */
87
for
(i = 0xffff; i > 0; i--) {
/* Delay for XTAL to settle */
88
asm
(
"nop"
);
89
}
90
91
CCTL2 = CCIS0 + CM0 + CAP;
/* Define CCR2, CAP, ACLK */
92
TACTL = TASSEL1 + TACLR + MC1;
/* SMCLK, continous mode */
93
94
95
while
(1) {
96
97
while
((CCTL2 & CCIFG) != CCIFG);
/* Wait until capture occured! */
98
CCTL2 &= ~CCIFG;
/* Capture occured, clear flag */
99
compare = CCR2;
/* Get current captured SMCLK */
100
compare = compare - oldcapture;
/* SMCLK difference */
101
oldcapture = CCR2;
/* Save current captured SMCLK */
102
103
if
(DELTA == compare) {
104
break
;
/* if equal, leave "while(1)" */
105
}
else
if
(DELTA < compare) {
/* DCO is too fast, slow it down */
106
DCOCTL--;
107
if
(DCOCTL == 0xFF) {
/* Did DCO role under? */
108
BCSCTL1--;
109
}
110
}
else
{
/* -> Select next lower RSEL */
111
DCOCTL++;
112
if
(DCOCTL == 0x00) {
/* Did DCO role over? */
113
BCSCTL1++;
114
}
115
/* -> Select next higher RSEL */
116
}
117
}
118
119
CCTL2 = 0;
/* Stop CCR2 function */
120
TACTL = 0;
/* Stop Timer_A */
121
122
BCSCTL1 &= ~(DIVA1 + DIVA0);
/* remove /8 divisor from ACLK again */
123
}
124
/*---------------------------------------------------------------------------*/
125
static
void
126
init_ports
(
void
)
127
{
128
/* Turn everything off, device drivers enable what is needed. */
129
130
/* All configured for digital I/O */
131
#ifdef P1SEL
132
P1SEL = 0;
133
#endif
134
#ifdef P2SEL
135
P2SEL = 0;
136
#endif
137
#ifdef P3SEL
138
P3SEL = 0;
139
#endif
140
#ifdef P4SEL
141
P4SEL = 0;
142
#endif
143
#ifdef P5SEL
144
P5SEL = 0;
145
#endif
146
#ifdef P6SEL
147
P6SEL = 0;
148
#endif
149
150
/* All available inputs */
151
#ifdef P1DIR
152
P1DIR = 0;
153
P1OUT = 0;
154
#endif
155
#ifdef P2DIR
156
P2DIR = 0;
157
P2OUT = 0;
158
#endif
159
#ifdef P3DIR
160
P3DIR = 0;
161
P3OUT = 0;
162
#endif
163
#ifdef P4DIR
164
P4DIR = 0;
165
P4OUT = 0;
166
#endif
167
168
#ifdef P5DIR
169
P5DIR = 0;
170
P5OUT = 0;
171
#endif
172
173
#ifdef P6DIR
174
P6DIR = 0;
175
P6OUT = 0;
176
#endif
177
178
#ifdef P7DIR
179
P7DIR = 0;
180
P7OUT = 0;
181
#endif
182
183
#ifdef P8DIR
184
P8DIR = 0;
185
P8OUT = 0;
186
#endif
187
188
P1IE = 0;
189
P2IE = 0;
190
}
191
/*---------------------------------------------------------------------------*/
192
/* msp430-ld may align _end incorrectly. Workaround in cpu_init. */
193
#if defined(__MSP430__) && defined(__GNUC__)
194
extern
int
_end;
/* Not in sys/unistd.h */
195
static
char
*cur_break = (
char
*)&_end;
196
#endif
197
198
/*---------------------------------------------------------------------------*/
199
/* add/remove_lpm_req - for requiring a specific LPM mode. currently Contiki */
200
/* jumps to LPM3 to save power, but DMA will not work if DCO is not clocked */
201
/* so some modules might need to enter their LPM requirements */
202
/* NOTE: currently only works with LPM1 (e.g. DCO) requirements. */
203
/*---------------------------------------------------------------------------*/
204
void
205
msp430_add_lpm_req(
int
req)
206
{
207
if
(req <= MSP430_REQUIRE_LPM1) {
208
msp430_dco_required++;
209
}
210
}
211
212
void
213
msp430_remove_lpm_req(
int
req)
214
{
215
if
(req <= MSP430_REQUIRE_LPM1) {
216
msp430_dco_required--;
217
}
218
}
219
220
void
221
msp430_cpu_init(
void
)
222
{
223
dint();
224
watchdog_init
();
225
init_ports
();
226
msp430_init_dco
();
227
eint();
228
#if defined(__MSP430__) && defined(__GNUC__)
229
if
((uintptr_t)cur_break & 1) {
/* Workaround for msp430-ld bug! */
230
cur_break++;
231
}
232
#endif
233
234
msp430_dco_required = 0;
235
}
236
/*---------------------------------------------------------------------------*/
237
238
#define STACK_EXTRA 32
239
240
/*
241
* Allocate memory from the heap. Check that we don't collide with the
242
* stack right now (some other routine might later). A watchdog might
243
* be used to check if cur_break and the stack pointer meet during
244
* runtime.
245
*/
246
#if defined(__MSP430__) && defined(__GNUC__)
247
void
*
248
sbrk(
int
incr)
249
{
250
char
*stack_pointer;
251
252
asmv(
"mov r1, %0"
:
"=r"
(stack_pointer));
253
stack_pointer -= STACK_EXTRA;
254
if
(incr > (stack_pointer - cur_break))
255
return
(
void
*)-1;
/* ENOMEM */
256
257
void
*old_break = cur_break;
258
cur_break += incr;
259
/*
260
* If the stack was never here then [old_break .. cur_break] should
261
* be filled with zeros.
262
*/
263
return
old_break;
264
}
265
#endif
266
/*---------------------------------------------------------------------------*/
267
/*
268
* Mask all interrupts that can be masked.
269
*/
270
int
271
splhigh_
(
void
)
272
{
273
int
sr;
274
/* Clear the GIE (General Interrupt Enable) flag. */
275
#ifdef __IAR_SYSTEMS_ICC__
276
sr = __get_SR_register();
277
__bic_SR_register(GIE);
278
#else
279
asmv(
"mov r2, %0"
:
"=r"
(sr));
280
asmv(
"bic %0, r2"
: :
"i"
(GIE));
281
/* GCC 9 warns about risk of incorrect execution without nop after
282
interrupt state changes. */
283
asmv(
"nop"
);
284
#endif
285
return
sr & GIE;
/* Ignore other sr bits. */
286
}
287
/*---------------------------------------------------------------------------*/
288
/*
289
* Restore previous interrupt mask.
290
*/
291
/* void */
292
/* splx_(int sr) */
293
/* { */
294
/* #ifdef __IAR_SYSTEMS_ICC__ */
295
/* __bis_SR_register(sr); */
296
/* #else */
297
/* /\* If GIE was set, restore it. *\/ */
298
/* asmv("bis %0, r2" : : "r" (sr)); */
299
/* #endif */
300
/* } */
301
/*---------------------------------------------------------------------------*/
302
#ifdef __IAR_SYSTEMS_ICC__
303
int
__low_level_init(
void
)
304
{
305
/* turn off watchdog so that C-init will run */
306
WDTCTL = WDTPW + WDTHOLD;
307
/*
308
* Return value:
309
*
310
* 1 - Perform data segment initialization.
311
* 0 - Skip data segment initialization.
312
*/
313
return
1;
314
}
315
#endif
316
/*---------------------------------------------------------------------------*/
317
#if DCOSYNCH_CONF_ENABLED
318
/* this code will always start the TimerB if not already started */
319
void
320
msp430_sync_dco
(
void
) {
321
uint16_t last;
322
uint16_t diff;
323
/* uint32_t speed; */
324
/* DELTA_2 assumes an ACLK of 32768 Hz */
325
#define DELTA_2 ((MSP430_CPU_SPEED) / 32768)
326
327
/* Select SMCLK clock, and capture on ACLK for TBCCR6 */
328
TBCTL = TBSSEL1 | TBCLR;
329
TBCCTL6 = CCIS0 + CM0 + CAP;
330
/* start the timer */
331
TBCTL |= MC1;
332
333
/* wait for next Capture */
334
TBCCTL6 &= ~CCIFG;
335
while
(!(TBCCTL6 & CCIFG));
336
last = TBCCR6;
337
338
TBCCTL6 &= ~CCIFG;
339
/* wait for next Capture - and calculate difference */
340
while
(!(TBCCTL6 & CCIFG));
341
diff = TBCCR6 - last;
342
343
/* Stop timer - conserves energy according to user guide */
344
TBCTL = 0;
345
346
/* speed = diff; */
347
/* speed = speed * 32768; */
348
/* printf("Last TAR diff:%d target: %ld ", diff, DELTA_2); */
349
/* printf("CPU Speed: %lu DCOCTL: %d\n", speed, DCOCTL); */
350
351
/* resynchronize the DCO speed if not at target */
352
if
(DELTA_2 < diff) {
/* DCO is too fast, slow it down */
353
DCOCTL--;
354
if
(DCOCTL == 0xFF) {
/* Did DCO role under? */
355
BCSCTL1--;
356
}
357
}
else
if
(DELTA_2 > diff) {
358
DCOCTL++;
359
if
(DCOCTL == 0x00) {
/* Did DCO role over? */
360
BCSCTL1++;
361
}
362
}
363
}
364
#endif
/* DCOSYNCH_CONF_ENABLED */
365
/*---------------------------------------------------------------------------*/
value
static int value(int type)
Definition
cc2538-temp-sensor.c:49
watchdog_init
void watchdog_init(void)
Initialisation function for the WDT.
Definition
watchdog.c:63
msp430_init_dco
static void msp430_init_dco(void)
Initialize the Clock System (CS) module.
Definition
msp430.c:60
init_ports
static void init_ports(void)
Initialize all ports to output low to reduce power consumption.
Definition
msp430.c:124
splhigh_
int splhigh_(void)
Mask all interrupts that can be masked.
Definition
msp430.c:166
msp430_sync_dco
void msp430_sync_dco(void)
Synchronize DCO (no-op for FR5969, DCO is automatically calibrated).
Definition
msp430.c:157
arch
cpu
msp430
f1xxx
msp430.c
Generated on
for Contiki-NG by
1.17.0