MSP430 Programming and Debugging

(on linux)

The MSP430 launchpad is a low cost, low power microcontroller that can be used in a variety of embedded applications. This post documents how to program and flash the device on linux without TI’s IDE.

Note: the specific MSP430 device I’m using is msp430g2553.

Tools used

In addition to GNU Make, I installed these packages to cross compile, flash, and debug.

udev

This is optional, but if you want to program your microcontroller without sudo permissions, it would be a good idea to add a udev rule that will put the device in a group you are apart of. I chose wheel but you can use your own username or create a whole new group.

/etc/udev/rules.d/91-ti-launchpad.rules

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="f432", \
GROUP="wheel", MODE="0660"

Note: the idVendor and idProduct values can be found via lsusb (from the core/usbutils package on Arch) in the form ID idVendor:idProduct, but the values here should match all MSP430 IDs.

To reload your new rule, you can run:

sudo udevadm control --reload

Makefile

I copied this Makefile example and made some modifications to use the tools we are using. Things to note are MCU, SOURCES, INCLUDES.

#
# Makefile for msp430
#
# 'make' builds everything
# 'make clean' deletes everything except source files and Makefile
# You need to set TARGET, MCU and SOURCES for your project.
# TARGET is the name of the executable file to be produced
# $(TARGET).elf $(TARGET).hex and $(TARGET).txt and $(TARGET).map are all generated.
# The TXT file is used for BSL loading, the ELF can be used for JTAG use
#
TARGET     = blinky
MCU        = msp430g2553
# List all the source files here
# eg if you have a source file foo.c then list it here
SOURCES = blinky.c
# Include are located in the Include directory
INCLUDES = -I/opt/ti/mspgcc/include -L/opt/ti/mspgcc/include
# Add or subtract whatever MSPGCC flags you want. There are plenty more
#######################################################################################
DEBUG    = -g3 -ggdb -gdwarf-2
CFLAGS   = -mmcu=$(MCU) -Os -Wall -Wunused $(INCLUDES) $(DEBUG)
ASFLAGS  = -mmcu=$(MCU) -x assembler-with-cpp -Wa,-gstabs
LDFLAGS  = -mmcu=$(MCU) -Wl,-Map=$(TARGET).map
########################################################################################
CC       = msp430-elf-gcc
LD       = msp430-elf-ld
AR       = msp430-elf-ar
AS       = msp430-elf-gcc
GASP     = msp430-elf-gasp
NM       = msp430-elf-nm
OBJCOPY  = msp430-elf-objcopy
RANLIB   = msp430-elf-ranlib
STRIP    = msp430-elf-strip
SIZE     = msp430-elf-size
READELF  = msp430-elf-readelf
MAKETXT  = srec_cat
CP       = cp -p
RM       = rm -f
MV       = mv
########################################################################################
# the file which will include dependencies
DEPEND = $(SOURCES:.c=.d)
# all the object files
OBJECTS = $(SOURCES:.c=.o)
all: $(TARGET).elf $(TARGET).hex $(TARGET).txt
$(TARGET).elf: $(OBJECTS)
	echo "Linking $@"
	$(CC) $(OBJECTS) $(LDFLAGS) $(LIBS) -o $@
	echo
	echo ">>>> Size of Firmware <<<<"
	$(SIZE) $(TARGET).elf
	echo
%.hex: %.elf
	$(OBJCOPY) -O ihex $< $@
%.txt: %.hex
	$(MAKETXT) -O $@ -TITXT $< -I
%.o: %.c
	echo "Compiling $<"
	$(CC) -c $(CFLAGS) -o $@ $<
# rule for making assembler source listing, to see the code
%.lst: %.c
	$(CC) -c $(CFLAGS) -Wa,-anlhd $< > $@
# include the dependencies unless we're going to clean, then forget about them.
ifneq ($(MAKECMDGOALS), clean)
-include $(DEPEND)
endif
# dependencies file
# includes also considered, since some of these are our own
# (otherwise use -MM instead of -M)
%.d: %.c
	echo "Generating dependencies $@ from $<"
	$(CC) -M ${CFLAGS} $< >$@
.SILENT:
.PHONY:	clean
clean:
	-$(RM) $(OBJECTS)
	-$(RM) $(TARGET).map
	-$(RM) $(TARGET).elf $(TARGET).hex $(TARGET).txt
	-$(RM) $(TARGET).lst
	-$(RM) $(SOURCES:.c=.lst)
	-$(RM) $(DEPEND)

.PHONY: flash
flash: $(TARGET).hex
	mspdebug rf2500 'prog $<'

.PHONY: debug
debug: $(TARGET).elf
	mspdebug rf2500 'gdb' >/dev/null 2>&1 &
	msp430-gdb $< -ex 'target remote :2000'

C sources

Here’s my “hello world” blinky program. The first step to embedded development is to usually disable the watchdog timer, which is essentially a timer that will reset the board after a fairly short time. We then need to configure the GPIO port and pin to be an output, and finally we can control the state of the LED by writing to P1OUT.

#include "msp430.h"
/* #include "msp430g2553.h" */

int main() {
    // disable watchdog timer
    WDTCTL = WDTPW | WDTHOLD;
    // set P1.0 to be an output
    P1DIR |= 0x1;

    while (1) {
        // toggle P1.0
        P1OUT ^= 0x1;

        // software delay
        for (volatile int i = 0; i < 20000; i++);
    }
}

Note: I develop in vim with ALE, so to tell ALE where to find the includes I added the following to my .vimrc (matching the Makefile). This is just for the linter; compiling works regardless.

let g:ale_c_cc_options="-I/opt/ti/mspgcc/include"

GDB

The above Makefile includes a debug recipe which spawns mspedubg in GDB mode, then starts GDB and automatically connects to the default listen port of 2000. It’s important to compile our program with debug symbols (-g3, -ggdb, -gdwarf-2) to get a rich debug environment.

It should be noted that the debugger (included in the MSP430 launchpad) is running on the actual hardware, which means we can examine and modify registers directly through GDB interactively! For example the following commands will configure the second LED pin (which is on P1.6) and toggle it.

(gdb) set P1DIR |= (1 << 6)
(gdb) set P1OUT ^= (1 << 6)

Conclusion

These steps document how to build and flash an MSP430 board using available open source tools. Future posts will cover more in depth features of the MSP430.