board.c 4.01 KB
/*
 * board.c - Board initiazilation for the TelosB
 * Copyright (C) 2013 Oliver Hahm <oliver.hahm@inria.fr>
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

#include "cpu.h"
#include "board.h"
#include "uart_stdio.h"

void uart_init(void);

static void telosb_ports_init(void)
{
    /* Port 1: GDO, Flash, BSL TX */
    P1SEL = 0x02;    /* Port1 Select: 00000010 = 0x02 */
    P1OUT = 0x00;    /* Port1 Output: 00000000 = 0x00 */
    P1DIR = 0x87;    /* Port1 Direction: 10000111 = 0x87 */

    /* Port 2: GPIO, BSL RX, 1wire */
    P2SEL = 0x04;    /* Port2 Select: 00000100 = 0x04 */
    P2OUT = 0x00;    /* Port2 Output: 00000000 = 0x00 */
    P2DIR = 0xFF;    /* Port2 Direction: 11111111 = 0xFF */

    /* Port 3: UART and SPI */
    P3SEL = 0x0E;    /* Port3 Select: 11001110 = 0xCE */
    P3OUT = 0x00;    /* Port3 Output: 00000000 = 0x00 */
    P3DIR = 0xFE;    /* Port3 Direction: 01001110 = 0x4E */

    /* Port 4: CS */
    P4SEL = 0x02;    /* Port4 Select: 00000010 = 0x02 */
    P4OUT = 0x04;    /* Port4 Output: 00000100 = 0x04 */
    P4DIR = 0x64;    /* Port4 Direction: 01100100 = 0x64 */

    /* Port 5: SPI, LED */
    P5SEL = 0x00;    /* Port5 Select: 00000000 = 0x00 */
    P5OUT = 0x70;    /* Port5 Output: 01110000 = 0x70 */
    P5DIR = 0x70;    /* Port5 Direction: 01110000 = 0x70 */


    P6SEL = 0xFF;    /* Port6 Select: 11111111 = 0xFF */
    P6OUT = 0x00;    /* Port6 Output: 00000000 = 0x00 */
    P6DIR = 0xFF;    /* Port6 Direction: 11111000 = 0xFF */

}

/*---------------------------------------------------------------------------*/
/* taken from Contiki code */
void msp430_init_dco(void)
{
    /* This code taken from the FU Berlin sources and reformatted. */
#define DELTA    (F_CPU / (F_RC_OSCILLATOR / 8))

    unsigned int oldcapture = 0;
    unsigned int i;

    /* 10100100 = XT2 is off, ACLK divided by 4, RSELx=4 */
    BCSCTL1 = XT2OFF | DIVA_2 | RSEL2;

    /* Init undivided DCO with internal resistor for MCLK and SMCLK
     * DCO = 32762Hz -> FLL = 2,4576 MHz */
    BCSCTL2 = 0x00;

    BCSCTL1 |= DIVA1 + DIVA0;             /* ACLK = LFXT1CLK/8 */

    for (i = 0xFFFF; i > 0; i--) {        /* Delay for XTAL to settle */
        __asm__("nop");
    }

    CCTL2 = CCIS0 + CM0 + CAP;            /* Define CCR2, CAP, ACLK */
    TACTL = TASSEL1 + TACLR + MC1;        /* SMCLK, continous mode */

    while (1) {
        unsigned int compare;

        while ((CCTL2 & CCIFG) != CCIFG);   /* Wait until capture occured!*/

        CCTL2 &= ~CCIFG;                    /* Capture occured, clear flag */
        compare = CCR2;                     /* Get current captured SMCLK */
        compare = compare - oldcapture;     /* SMCLK difference */
        oldcapture = CCR2;                  /* Save current captured SMCLK */

        if (DELTA == compare) {
            break;                            /* if equal, leave "while (1)" */
        }
        else if (DELTA < compare) {        /* DCO is too fast, slow it down */
            DCOCTL--;

            if (DCOCTL == 0xFF) {             /* Did DCO role under? */
                BCSCTL1--;
            }
        }
        else {                            /* -> Select next lower RSEL */
            DCOCTL++;

            if (DCOCTL == 0x00) {             /* Did DCO role over? */
                BCSCTL1++;
            }

            /* -> Select next higher RSEL  */
        }
    }

    CCTL2 = 0;                            /* Stop CCR2 function */
    TACTL = 0;                            /* Stop Timer_A */

    BCSCTL1 &= ~(DIVA1 + DIVA0);          /* remove /8 divisor from ACLK again */
}


//=========================== public ==========================================

void board_init(void)
{
    msp430_cpu_init();
    /* disable watchdog timer */
    WDTCTL     =  WDTPW + WDTHOLD;

    telosb_ports_init();
    msp430_init_dco();

    /* initialize STDIO over UART */
    uart_stdio_init();

    /* enable interrupts */
    __bis_SR_register(GIE);
}