diff --git a/Makefile.base b/Makefile.base index a9a5375397..641eaf56cd 100644 --- a/Makefile.base +++ b/Makefile.base @@ -13,6 +13,10 @@ ifeq ($(BOARD),msb-430h) INCLUDES += -I$(RIOTBOARD)/msb-430-common/include/ INCLUDES += -I$(RIOTBOARD)/msb-430-common/drivers/include/ endif +ifeq ($(BOARD),wsn430-v1_3b) + INCLUDES += -I$(RIOTBOARD)/wsn430-v1_3b/include/ + INCLUDES += -I$(RIOTBOARD)/wsn430-common/include/ +endif ifeq ($(BOARD),chronos) INCLUDES += -I$(RIOTBOARD)/chronos/include/ INCLUDES += -I$(RIOTBOARD)/chronos/drivers/include/ diff --git a/wsn430-common/Makefile b/wsn430-common/Makefile new file mode 100644 index 0000000000..8f8f23add9 --- /dev/null +++ b/wsn430-common/Makefile @@ -0,0 +1,33 @@ +SRC = $(wildcard *.c) +BINDIR = $(RIOTBOARD)/$(BOARD)/bin/ +OBJ = $(SRC:%.c=$(BINDIR)%.o)## defines +DEP = $(SRC:%.c=$(BINDIR)%.d) + +INCLUDES += -I$(RIOTBOARD)/wsn430-common/include/ -I${RIOTBOARD}/${BOARD}/include/ +INCLUDES += -I$(RIOTBASE)/cpu/msp430-common/include/ +INCLUDES += -I$(RIOTBASE)/cpu/mspx16x/include/ +INCLUDES += -I$(RIOTBASE)/drivers/include/ + +.PHONY: $(BINDIR)$(ARCH) + +all: $(BINDIR)$(ARCH) + #$(MAKE) -C drivers + +$(BINDIR)$(ARCH): $(OBJ) + echo $(AR) rcs $(BINDIR)$(ARCH) $(OBJ) + $(AR) rcs $(BINDIR)$(ARCH) $(OBJ) + +# pull in dependency info for *existing* .o files +-include $(OBJ:.o=.d) + +# compile and generate dependency info +$(BINDIR)%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) $(BOARDINCLUDE) $(PROJECTINCLUDE) $(CPUINCLUDE) -c $*.c -o $(BINDIR)$*.o + $(CC) $(CFLAGS) $(INCLUDES) $(BOARDINCLUDE) $(PROJECTINCLUDE) $(CPUINCLUDE) -MM $*.c > $(BINDIR)$*.d + @printf "$(BINDIR)"|cat - $(BINDIR)$*.d > /tmp/riot_out && mv /tmp/riot_out $(BINDIR)$*.d + +# remove compilation products +clean: + #$(MAKE) -C drivers clean + rm -f $(OBJ) $(DEP) + rm -f $(BINDIR)$(ARCH) diff --git a/wsn430-common/Makefile.include b/wsn430-common/Makefile.include new file mode 100644 index 0000000000..63cee9a3af --- /dev/null +++ b/wsn430-common/Makefile.include @@ -0,0 +1,23 @@ +## the cpu to build for +export CPU = msp430x16x +export MCU = msp430f1611 + +# toolchain config +export PREFIX = @msp430- +export CC = @$(PREFIX)gcc +export AR = @$(PREFIX)ar +export CFLAGS += -std=gnu99 -Wstrict-prototypes -gdwarf-2 -Os -Wall -mmcu=$(MCU) +export ASFLAGS += -mmcu=$(MCU) --defsym $(MCU)=1 --gdwarf-2 +export AS = $(PREFIX)as +export LINK = $(PREFIX)gcc +export SIZE = $(PREFIX)size +export OBJCOPY = $(PREFIX)objcopy +export LINKFLAGS = -mmcu=$(MCU) -lgcc $(RIOTBASE)/bin/startup.o +export FLASHER = mspdebug +ifeq ($(strip $(PORT)),) + export PORT = /dev/ttyUSB0 +endif +export HEXFILE = bin/$(PROJECT).hex +export FFLAGS = -d $(PORT) -j uif "prog $(HEXFILE)" + +export INCLUDES += -I $(RIOTCPU)/msp430-common/include/ \ No newline at end of file diff --git a/wsn430-common/board_config.c b/wsn430-common/board_config.c new file mode 100644 index 0000000000..f22e513b20 --- /dev/null +++ b/wsn430-common/board_config.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +void config_load(void) { + if (*((uint16_t*) INFOMEM) == CONFIG_KEY) { + memcpy(&sysconfig, (char*) (INFOMEM + sizeof(CONFIG_KEY)), sizeof(sysconfig)); + } + else { + config_save(); + } +} + +uint8_t config_save(void) { + configmem_t mem = { CONFIG_KEY, sysconfig }; + return (flashrom_erase((uint8_t*) INFOMEM) && flashrom_write((uint8_t*) INFOMEM, (char*) &mem, sizeof(mem))); +} diff --git a/wsn430-common/board_init.c b/wsn430-common/board_init.c new file mode 100644 index 0000000000..b7b523cf76 --- /dev/null +++ b/wsn430-common/board_init.c @@ -0,0 +1,150 @@ + /* + * board_init.c - Implementation of functions to init board. + * Copyright (C) 2013 Milan Babel + * + * This source code is licensed under the GNU General Public License, + * Version 3. See the file LICENSE for more details. + */ + +#include "cpu.h" +#include "board.h" +#include "kernel_intern.h" +#include "msp430.h" +#include "debug.h" + +volatile static uint32_t __msp430_cpu_speed = MSP430_INITIAL_CPU_SPEED; + +typedef enum { + MCLK_2MHZ_SCLK_1MHZ = 1000002uL, + MCLK_4MHZ_SCLK_1MHZ = 1000004uL, + MCLK_8MHZ_SCLK_1MHZ = 1000008uL, + MCLK_8MHZ_SCLK_8MHZ = 8000000uL +}speed_t; + +/*---------------------------------------------------------------------------*/ +static uint8_t calc_umctl(uint16_t br) { + // from TI slaa049 + register uint8_t CMOD = 256 * br - 256 * (br + 1) / 2; + register uint8_t c = 0; + register int i = 0; + register uint8_t a = CMOD; + a <<= 1; + do { + if( a & 0x80 ) { // Overflow to integer? + a = a - 128 + CMOD; // Yes, subtract 1.000000 + c |= 0x80; + } else { + a += CMOD; // No, add fraction + } + if( i == 7 ) { + return c; + } + i++; + c >>= 1; + } while(1); +} + +static void msb_ports_init(void) +{ + // Port 1: GDO, Flash, BSL TX + P1SEL = 0x02; // Port1 Select: 00000010 = 0x02 + P1OUT = 0x00; // Port1 Output: 00000000 = 0x00 + P1DIR = 0xE7; // Port1 Direction: 11100111 = 0xE7 + + // 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 + P3SEL = 0xFE; // Port3 Select: 11111110 = 0xFE + P3OUT = 0x00; // Port3 Output: 00000000 = 0x00 + P3DIR = 0xFF; // Port3 Direction: 11111111 = 0xFF + + + // Port 4: CS + P4SEL = 0x00; // Port4 Select: 00000000 = 0x00 + P4OUT = 0x14; // Port4 Output: 00010100 = 0x14 + P4DIR = 0xFF; // Port4 Direction: 11111111 = 0xFF + + // Port 5: SPI, LED + P5SEL = 0x0E; // Port5 Select: 00001110 = 0x0E + 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 = 0xF8 + +} + +void msp430_set_cpu_speed(uint32_t speed) +{ + + dint(); + __msp430_cpu_speed = speed; + msp430_init_dco(); + uint16_t br; + + U0CTL = SWRST; + U0CTL = SWRST | CHAR; // 8-bit character + U0TCTL = SSEL1 | TXEPT; // UCLK = SCLK + U0RCTL = 0; + // activate + ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD + br = (uint16_t)((__msp430_cpu_speed & 0xFFFFF0) / 115200uL); + UBR00 = br; // set baudrate + UBR10 = br>>8; + UMCTL0 = calc_umctl(br); // set modulation + + U0CTL &= ~SWRST; + + //URCTL0 |= URXEIE; // allow chars to interrupt + IE1 |= URXIE0; // enable rx interrupt + IFG1 &= ~UTXIFG0; + eint(); +} + +/*---------------------------------------------------------------------------*/ +void msp430_init_dco(void) +{ + /*----------------------- use external oszillator -------------------------*/ + uint16_t i; + + // Stop watchdog + WDTCTL = WDTPW + WDTHOLD; + + BCSCTL1 = RSEL2; + + // Wait for xtal to stabilize + do { + IFG1 &= ~OFIFG; // Clear oscillator fault flag + for (i = 0xFF; i > 0; i--); // Time for flag to set + } + while ((IFG1 & OFIFG) != 0); // Oscillator fault flag still set? + switch (__msp430_cpu_speed) { + case MCLK_2MHZ_SCLK_1MHZ: + BCSCTL2 = (SELM_2 | DIVM_2) | (SELS | DIVS_3); + break; + case MCLK_4MHZ_SCLK_1MHZ: + BCSCTL2 = (SELM_2 | DIVM_1) | (SELS | DIVS_3); + break; + case MCLK_8MHZ_SCLK_1MHZ: + BCSCTL2 = SELM_2 | (SELS | DIVS_3); + break; + default: + BCSCTL2 = SELM_2 + SELS; // MCLK and SMCLK = XT2 (safe) + break; + } +} + +void board_init() { + msp430_cpu_init(); + msb_ports_init(); + + LED_RED_ON; + + msp430_set_cpu_speed(MCLK_8MHZ_SCLK_8MHZ); +} diff --git a/wsn430-common/drivers/Makefile b/wsn430-common/drivers/Makefile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wsn430-common/include/board-conf.h b/wsn430-common/include/board-conf.h new file mode 100644 index 0000000000..e85c3128f2 --- /dev/null +++ b/wsn430-common/include/board-conf.h @@ -0,0 +1,6 @@ +#ifndef BOARD_CONF_H +#define BOARD_CONF_H + +#define INFOMEM (0x1000) + +#endif /* BOARD-CONF_H */ diff --git a/wsn430-common/uart0.c b/wsn430-common/uart0.c new file mode 100644 index 0000000000..f743335ec4 --- /dev/null +++ b/wsn430-common/uart0.c @@ -0,0 +1,63 @@ + /* + * uart0.c - Implementation of the uart. + * Copyright (C) 2013 Milan Babel + * + * This source code is licensed under the GNU General Public License, + * Version 3. See the file LICENSE for more details. + */ + +#include "board.h" + +#define UART0_TX U0TXBUF +#define UART0_WAIT_TXDONE() while( (U0TCTL & TXEPT) == 0 ) { _NOP(); } + +#include +#include + +#include + +int putchar(int c) +{ + UART0_TX = c; + UART0_WAIT_TXDONE(); + + if (c == 10) { + UART0_TX = 13; + UART0_WAIT_TXDONE(); + } + + return c; +} + +void usart0irq(void); +/** + * \brief the interrupt function + */ +interrupt(USART0RX_VECTOR) usart0irq(void) { + int dummy = 0; + /* Check status register for receive errors. */ + if(U0RCTL & RXERR) { + if (U0RCTL & FE) { + puts("rx framing error"); + } + if (U0RCTL & OE) { + puts("rx overrun error"); + } + if (U0RCTL & PE) { + puts("rx parity error"); + } + if (U0RCTL & BRK) { + puts("rx break error"); + } + /* Clear error flags by forcing a dummy read. */ + dummy = U0RXBUF; + } +#ifdef MODULE_UART0 + else if (uart0_handler_pid) { + dummy = U0RXBUF; + uart0_handle_incoming(dummy); + uart0_notify_thread(); + } +#endif +} + diff --git a/wsn430-v1_3b/Makefile b/wsn430-v1_3b/Makefile new file mode 100644 index 0000000000..e19884c6b1 --- /dev/null +++ b/wsn430-v1_3b/Makefile @@ -0,0 +1,36 @@ +SRC = $(wildcard *.c) +BINDIR = bin/ +OBJ = $(SRC:%.c=$(BINDIR)%.o)## defines +export ARCH = wsn430-v1_3b_base.a + +DEP = $(SRC:%.c=$(BINDIR)%.d) + +INCLUDES += -I${RIOTBASE}/core/include/ +INCLUDES += -Iinclude/ -I$(RIOTBOARD)/wsn430-common/include/ +INCLUDES += -I$(RIOTBASE)/cpu/msp430-common/include/ -I$(RIOTBASE)/cpu/msp430x16x/include/ +INCLUDES += -I$(RIOTBASE)/drivers/cc110x_ng/include/ -I$(RIOTBASE)/sys/include +#INCLUDES += -I/usr/msp430/include/ + +all: $(BINDIR)$(ARCH) + $(MAKE) -C ../wsn430-common + +$(BINDIR)$(ARCH): $(OBJ) + $(AR) rcs $(BINDIR)$(ARCH) $(OBJ) + +# pull in dependency info for *existing* .o files +-include $(OBJ:.o=.d) + +# compile and generate dependency info +$(BINDIR)%.o: %.c + mkdir -p $(BINDIR) + $(CC) $(CFLAGS) $(INCLUDES) $(BOARDINCLUDE) $(PROJECTINCLUDE) $(CPUINCLUDE) -c $*.c -o $(BINDIR)$*.o + $(CC) $(CFLAGS) $(INCLUDES) $(BOARDINCLUDE) $(PROJECTINCLUDE) $(CPUINCLUDE) -MM $*.c > $(BINDIR)$*.d + @printf "$(BINDIR)"|cat - $(BINDIR)$*.d > /tmp/riot_out && mv /tmp/riot_out $(BINDIR)$*.d + +# remove compilation products +clean: + $(MAKE) -C ../wsn430-common clean + rm -f $(BINDIR)$(ARCH) $(OBJ) $(DEP) + @if [ -d $(BINDIR) ] ; \ + then rmdir $(BINDIR) ; \ + fi \ No newline at end of file diff --git a/wsn430-v1_3b/Makefile.dep b/wsn430-v1_3b/Makefile.dep new file mode 100644 index 0000000000..5463317289 --- /dev/null +++ b/wsn430-v1_3b/Makefile.dep @@ -0,0 +1,7 @@ +ifneq (,$(findstring cc110x_ng,$(USEMODULE))) + ifeq (,$(findstring cc110x_spi,$(USEMODULE))) + USEMODULE += cc110x_spi + endif +endif + +USEMODULE += msp430_common \ No newline at end of file diff --git a/wsn430-v1_3b/Makefile.include b/wsn430-v1_3b/Makefile.include new file mode 100644 index 0000000000..366d6cbcc8 --- /dev/null +++ b/wsn430-v1_3b/Makefile.include @@ -0,0 +1,3 @@ +include $(RIOTBOARD)/$(BOARD)/Makefile.dep + +include $(RIOTBOARD)/wsn430-common/Makefile.include \ No newline at end of file diff --git a/wsn430-v1_3b/driver_cc110x.c b/wsn430-v1_3b/driver_cc110x.c new file mode 100644 index 0000000000..39ca90bb15 --- /dev/null +++ b/wsn430-v1_3b/driver_cc110x.c @@ -0,0 +1,206 @@ + /* + * driver_cc110x.c - Implementation of the board dependent cc1100 functions. + * Copyright (C) 2013 Milan Babel + * + * This source code is licensed under the GNU General Public License, + * Version 3. See the file LICENSE for more details. + */ + +#include + +#include +#include +#include + +#include +#include + +#define CC1100_GDO0 (P1IN & 0x08) // read serial I/O (GDO0) +#define CC1100_GDO1 (P5IN & 0x04) // read serial I/O (GDO1) +#define CC1100_GDO2 (P1IN & 0x10) // read serial I/O (GDO2) + +#define CC1100_CS_LOW (P4OUT &= ~0x04) +#define CC1100_CS_HIGH (P4OUT |= 0x04) + +#define CC1100_GDO1_LOW_COUNT (2700) // loop count (timeout ~ 500 us) to wait +#define CC1100_GDO1_LOW_RETRY (100) // max. retries for GDO1 to go low + +volatile int abort_count; +volatile int retry_count = 0; + +void cc110x_gdo0_enable(void) +{ + P1IFG &= ~0x08; /* Clear IFG for GDO0 */ + P1IE |= 0x08; /* Enable interrupt for GDO0 */ +} + +void cc110x_gdo0_disable(void) +{ + P1IE &= ~0x08; /* Disable interrupt for GDO0 */ + P1IFG &= ~0x08; /* Clear IFG for GDO0 */ +} + +void cc110x_gdo2_enable(void) +{ + P1IFG &= ~0x10; /* Clear IFG for GDO2 */ + P1IE |= 0x10; /* Enable interrupt for GDO2 */ +} + +void cc110x_gdo2_disable(void) +{ + P1IE &= ~0x10; /* Disable interrupt for GDO2 */ + P1IFG &= ~0x10; /* Clear IFG for GDO2 */ +} + +void cc110x_before_send(void) +{ + // Disable GDO2 interrupt before sending packet + cc110x_gdo2_disable(); +} + +void cc110x_after_send(void) +{ + // Enable GDO2 interrupt after sending packet + cc110x_gdo2_enable(); +} + + +int cc110x_get_gdo0(void) { + return CC1100_GDO0; +} + +int cc110x_get_gdo1(void) { + return CC1100_GDO1; +} + +int cc110x_get_gdo2(void) { + return CC1100_GDO2; +} + +void cc110x_spi_cs(void) +{ + CC1100_CS_LOW; +} + +uint8_t cc110x_txrx(uint8_t data) +{ + /* Ensure TX Buf is empty */ + long c = 0; + IFG2 &= ~UTXIFG1; + IFG2 &= ~URXIFG1; + U1TXBUF = data; + while(!(IFG2 & UTXIFG1)) { + if (c++ == 1000000) { + puts("cc110x_txrx alarm()"); + } + } + /* Wait for Byte received */ + c = 0; + while(!(IFG2 & URXIFG1)) { + if (c++ == 1000000) { + puts("cc110x_txrx alarm()"); + } + } + return U1RXBUF; +} + + +void cc110x_spi_select(void) +{ + // Switch to GDO mode + P5SEL &= ~0x04; + P5DIR &= ~0x04; + cs_low: + // CS to low + abort_count = 0; + CC1100_CS_LOW; + // Wait for SO to go low (voltage regulator + // has stabilized and the crystal is running) + loop: +// asm volatile ("nop"); + if (CC1100_GDO1) { + abort_count++; + if (abort_count > CC1100_GDO1_LOW_COUNT) { + retry_count++; + if (retry_count > CC1100_GDO1_LOW_RETRY) { + puts("[CC1100 SPI] fatal error\n"); + goto final; + } + CC1100_CS_HIGH; + goto cs_low; // try again + } + goto loop; + } + final: + /* Switch to SPI mode */ + P5SEL |= 0x04; +} + +void cc110x_spi_unselect(void) { + CC1100_CS_HIGH; +} + +void cc110x_init_interrupts(void) +{ + unsigned int state = disableIRQ(); /* Disable all interrupts */ + P1SEL = 0x00; /* must be <> 1 to use interrupts */ + P1IES |= 0x10; /* Enables external interrupt on low edge (for GDO2) */ + P1IE |= 0x10; /* Enable interrupt */ + P1IFG &= ~0x10; /* Clears the interrupt flag */ + P1IE &= ~0x08; /* Disable interrupt for GDO0 */ + P1IFG &= ~0x08; /* Clear IFG for GDO0 */ + restoreIRQ(state); /* Enable all interrupts */ +} + +void cc110x_spi_init(uint8_t clockrate) +{ + // Switch off async UART + while(!(U1TCTL & TXEPT)); // Wait for empty UxTXBUF register + IE2 &= ~(URXIE1 + UTXIE1); // Disable USART1 receive&transmit interrupt + ME2 &= ~(UTXE1 + URXE1); + P5DIR |= 0x0A; // output for CLK and SIMO + P5DIR &= ~(0x04); // input for SOMI + P5SEL |= 0x0E; // Set pins as SPI + + // Keep peripheral in reset state + U1CTL = SWRST; + + // 8-bit SPI Master 3-pin mode, with SMCLK as clock source + // CKPL works also, but not CKPH+CKPL or none of them!! + U1CTL |= CHAR + SYNC + MM; + U1TCTL = CKPH + SSEL1 + SSEL0 + STC; + + // Ignore clockrate argument for now, just use clock source/2 + // SMCLK = 8 MHz + U1BR0 = 0x02; // Ensure baud rate >= 2 + U1BR1 = 0x00; + U1MCTL = 0x00; // No modulation + U1RCTL = 0x00; // Reset Receive Control Register + + // Enable SPI mode + ME2 |= USPIE1; + + // Release for operation + U1CTL &= ~SWRST; +} + +/* + * CC1100 receive interrupt + */ +interrupt (PORT1_VECTOR) __attribute__ ((naked)) cc110x_isr(void){ + __enter_isr(); + /* Check IFG */ + if ((P1IFG & 0x10) != 0) { + P1IFG &= ~0x10; + cc110x_gdo2_irq(); + } + else if ((P2IFG & 0x08) != 0) { + cc110x_gdo0_irq(); + P1IE &= ~0x08; // Disable interrupt for GDO0 + P1IFG &= ~0x08; // Clear IFG for GDO0 + } else { + puts("cc110x_isr(): unexpected IFG!"); + /* Should not occur - only GDO1 and GDO2 interrupts are enabled */ + } + __exit_isr(); +} diff --git a/wsn430-v1_3b/include/board.h b/wsn430-v1_3b/include/board.h new file mode 100644 index 0000000000..ad864e132e --- /dev/null +++ b/wsn430-v1_3b/include/board.h @@ -0,0 +1,31 @@ +#ifndef _MSB_BOARD_H +#define _MSB_BOARD_H + +//MSB430 core +#define MSP430_INITIAL_CPU_SPEED 800000uL +#define MSP430_HAS_DCOR 0 +#define MSP430_HAS_EXTERNAL_CRYSTAL 1 + +/* LEDs ports MSB430 */ +#define LEDS_PxDIR P5DIR +#define LEDS_PxOUT P5OUT +#define LEDS_CONF_RED 0x04 +#define LEDS_CONF_GREEN 0x05 +#define LEDS_CONF_BLUE 0x06 + +#define LED_RED_ON LEDS_PxOUT &=~LEDS_CONF_RED +#define LED_RED_OFF LEDS_PxOUT |= LEDS_CONF_RED +#define LED_RED_TOGGLE LEDS_PxOUT ^= LEDS_CONF_RED + +#define LED_GREEN_ON LEDS_PxOUT &=~LEDS_CONF_GREEN +#define LED_GREEN_OFF LEDS_PxOUT |= LEDS_CONF_GREEN +#define LED_GREEN_TOGGLE LEDS_PxOUT ^= LEDS_CONF_GREEN + +#define LED_BLUE_ON LEDS_PxOUT &=~LEDS_CONF_BLUE +#define LED_BLUE_OFF LEDS_PxOUT |= LEDS_CONF_BLUE +#define LED_BLUE_TOGGLE LEDS_PxOUT ^= LEDS_CONF_BLUE + +#include + +/** @} */ +#endif // _MSB_BOARD_H