MSP430 programming using GAS

The executable as produced by GCC uses 218 bytes of program code and 2 bytes of RAM. There were no variables in the C program, so this variable comes from the MSP430 C framework. (Actually, it is used to keep the watchdog alive while starting up the program.)

Can we get the executable even smaller? The time has come for us to try some assembler programming. As we will see, when using the GNU assembler to work with include files that have been converted from use with the Texas Instruments tool suites to the GNU C compiler, there are a few aspects that might not have been solved as smoothly as possible. Still, one of the points of this exercise is to use the standard distribution as it was installed by the Ubuntu packages.

$ cd msp430/cycle_led_asm/
$ less cycle_led.asm

As we can see, the code is pretty much based on the previous C version. Some comments on things that are worthy of notice:

#include <msp430g2553.h>

We have actually run in to difficulties right away. Normally, we would expect to be able to use the assemblers include directive, but if we change this line to

.include "msp430g2553.h"

and then run the assembler

$ msp430-as -I /usr/msp430/include cycle_led.asm
/usr/msp430/include/msp430g2553.h: Assembler messages:
/usr/msp430/include/msp430g2553.h:55: Error: unknown opcode `extern'
/usr/msp430/include/msp430g2553.h:135: Error: unknown opcode `sfrb(ie1,'
/usr/msp430/include/msp430g2553.h:142: Error: unknown opcode `sfrb(ifg1,'

we get a horrible batch of error messages. Regardless of the fact that the header file states that it supports assembler development, when using the GNU tools, this simply isn’t the case. The GNU assembler ignores the #ifdef __cplusplus on line 54 of the msp430g2553.h header file, and happily tries to parse the C++ code that follows, obviously resulting in errors. We need to preprocess the code in some way, so CPP should be able to solve our problems. We change the include statement back to the ‘#’ version.

$ cpp -I /usr/msp430/include cycle_led.asm > cycle_led.s
$ less cycle_led.s
# 1 "/usr/msp430/include/intrinsics.h" 1
# 47 "/usr/msp430/include/intrinsics.h"
void __nop (void);
void __dint (void);
void __eint (void);

We still have some C code in there. If we look in intrinsics.h it seems that we managed to overcome the #ifdef __cplusplus problem, but for some reason the symbol __ASSEMBLER__ is not defined. The way that the include file is written, missing this symbol definition leads to inclusion of C code. It turns out that CPP needs some more help to understand that this is an assembler file.

$ cpp -I /usr/msp430/include -x assembler-with-cpp cycle_led.asm > cycle_led.s
$ less cycle_led.s

Things are looking much better now. This looks like a pure assembler file, so maybe we can get it to assemble?

$ msp430-as cycle_led.s
cycle_led.asm: Assembler messages:
cycle_led.asm:32: Error: garbage after immediate: #_BIS_SR(((0x0080)+(0x0040)+(0x0020)+(0x0010)))

We can find the _BIS_SR() definition in msp430g2553.h, line 114. But looking at line 105, it seems that we are inside an #else branch using defines meant for C. On line 97, the condition used is #ifndef __STDC__. So even though we have used the -x assembler-with-cpp flag to CPP, it still has __STDC__ defined. Digging deep into the reference documentation for CPP, we find that the way to leave __STDC__ undefined is to use the -traditional-cpp flag.

$ cpp -I /usr/msp430/include -x assembler-with-cpp -traditional-cpp cycle_led.asm > cycle_led.s
$ msp430-as cycle_led.s
/usr/msp430/include/msp430g2553.h: Assembler messages:
/usr/msp430/include/msp430g2553.h:730: Error: junk at end of line, first unrecognized character is `/'

Back in the msp430g2553.h file, for some reason line 730 contains a C++ style //-comment. Apparently, CPP with -traditional-cpp does not remove C++ style comments. This means that we end up with a two-step solution – run CPP once with the -traditional-cpp to avoid including C code that we get from __STDC__ being defined, and once without -traditional-cpp to remove C++ comments.

$ cpp -I /usr/msp430/include -x assembler-with-cpp -traditional-cpp cycle_led.asm > cycle_led.asmx
$ cpp -I /usr/msp430/include -x assembler-with-cpp cycle_led.asmx > cycle_led.s
$ msp430-as cycle_led.s

Phew! We had to do a lot of work to get around some of the tool limitations and some decisions in the header files that were not really optimized for the GNU toolchain. (We could execute CPP just once by undefining __STDC__ on the command line, but that results in a warning that is not possible to disable, so I find the result not to be as clean as this solution.)

Moving on to some more comments about the program itself.

    mov     #(WDTPW | WDTHOLD), &WDTCTL

The .text segment will be placed in flash memory, so this is where we should be outputting our program to.

    bis.b   #(GREEN_LED | RED_LED), &P1DIR
    bic.b   #BUTTON, &P1DIR

BIS and BIC are really useful bit set and clear instructions. When accessing hardware, there is always the question about whether to set bits directly at the device register address, or to read the device register into a processor register, modify it, and write it back. An instruction that affects a device register should use the absolute addressing mode, so it will be slower and take up more program memory than the corresponding processor register access function, but the latter needs two extra instructions to read in and write back the contents.

    bit.b   #BUTTON, &P1IFG

As in the C program, there is an interrupt routine that handles the cycling through the LED states when the button is pushed.

    .section .vectors, "a"
    .word   isr_end     ; 0xFFFC Non-maskable
    .word   main        ; 0xFFFE Reset

GCC is set up to generate the interrupt vector for us automatically, so when programming in assembler we need to set it up ourselves. The .vectors section will be placed at the interrupt vector area at the top of flash memory. It also needs to have the “a” attribute in order to actually be loaded by mspdebug. All that remains is to build. After that, we can download the code to the Launchpad using mspdebug, the same way as we did for the C program.

$ make
cpp -I /usr/msp430/include -x assembler-with-cpp -traditional-cpp cycle_led.asm > cycle_led.asmx 
cpp -I /usr/msp430/include -x assembler-with-cpp cycle_led.asmx > cycle_led.s 
msp430-as -mmcu=msp430g2553 -mcpu=430 -mmpy=none -o cycle_led.o cycle_led.s
msp430-ld -L /usr/msp430/lib/ldscripts/msp430g2553 -o cycle_led.elf cycle_led.o

   text	   data	    bss	    dec	    hex	filename
    114	      0	      0	    114	     72	cycle_led.elf

rm cycle_led.s cycle_led.asmx

We end up with an executable of 114 bytes, close to half the size of the C program. Well done!


MSP430 programming using GCC

We should try to compile some code for the Launchpad using GCC. I have prepared a tutorial project so it is not necessary to type any code – just compile and run it. Let us start by downloading the code. The code resides at GitHub, so we need the git tool to get it.

$ sudo apt-get install git
$ git clone https://github.com/integerring/msp430_tutorials.git msp430
$ ls msp430
cycle_led_asm  cycle_led_c  LICENSE.TXT  README.md

We can see that there are two directories for a project called “Cycle LED”, one using C and one using assembler. We leave the assembler for a coming tutorial, but let us try building the C project.

$ cd msp430/cycle_led_c/
$ make
msp430-gcc  -Os -Wall -g -mmcu=msp430g2553 -c cycle_led.c
msp430-gcc -Os -Wall -g -mmcu=msp430g2553 -o cycle_led.elf cycle_led.o
   text	   data	    bss	    dec	    hex	filename
    218	      0	      2	    220	     dc	cycle_led.elf

If all goes well during the compilation, we see that msp430-gcc has been used to compile cycle_led.c into cycle_led.o, and then to link cycle_led.o into cycle_led.elf. As a final step, I have set up msp430-size to display the size of the executable, 218 bytes of program plus 2 bytes of bss data. The bss section consists of uninitialized file-level variables and static local variables, that will be zero-initialized at runtime.

A couple of comments about some specific lines in the cycle_led.c file:

#include <msp430.h>
#include <isr_compat.h>

The msp430.h file will include a device-specific header file, depending on what the mcu argument is set to on the command line. The isr_compat.h file is included for having a convenient way of defining an interrupt routine. Also, it makes the code more compatible with different compilers, but this is not our main purpose right now.

#define RED_LED   BIT0
#define GREEN_LED BIT6
#define BUTTON    BIT3

Whereas the MSP-EXP430G2 LaunchPad User’s Guide p. 20 says that LED1 (bit 0) is green and LED2 (bit 6) is red, at least on my Launchpad LED1 is the red one and LED2 is the green one.


The MSP430 starts with the watchdog up and running, which will reset the board in 32768 clock cycles. The first thing we should do is reconfigure it or turn it off. Any writes to the watchdog must have a fixed “password” pattern in the upper bits, or the MSP will be reset upon write. (Although I believe it might also be possible to disable the watchdog using a compiler command line argument.)


A change from previous Launchpad versions to version 1.5 is that there is no external pull-up resistor for the push-button. Even though the user’s guide circuit diagram shows an R34 resistor for this purpose, there is no component soldered at R34. It also states in the beginning of the document that it has been removed to reduce power consumption. So instead we need to enable the internal resistor for this I/O pin (using P1REN) and set it to pull the pin high (using P1OUT). At first it seems somewhat counter-intuitive to write to the output for an input pin, but that is how we set the internal resistor to be pull-up or pull-down.

return 0;

We are using the input pin connected to the push-button to generate an interrupt, so we need to enable interrupts. Instead of entering an infinite loop at the end of the program, we can use one of the low-power modes to put the MSP to sleep until it is woken up by an interrupt. As we are not using any clocks for this program, we can use the lowest power mode, LPM4. This mode will then be resumed after an interrupt is handled, unless we change power mode in the interrupt routine, so we will never actually reach the return statement.

ISR(PORT1, button_press) {
  if (P1IFG & BUTTON) {

The MPS430 has a common interrupt vector used for all the I/O pins in port 1, so we should check whether the interrupt occurred from the pin that is connected to the button.

We can now run the compiled code on the Launchpad.

$ mspdebug rf2500
(mspdebug) prog cycle_led.elf
Writing  186 bytes to c000 [section: .text]...
Writing   32 bytes to ffe0 [section: .vectors]...
Done, 218 bytes written
(mspdebug) run
Running. Press Ctrl+C to interrupt...

Now press the left push-button on the Launchpad to see the LEDs light up in sequence: OFF – GREEN – RED – GREEN and RED – OFF. The right button will reset the Launchpad, which will interfere with running the software under a debugger.


MSP430 Launchpad development on Ubuntu

Given a nice installation of Ubuntu, what do we need to get started with MSP430 development? These instructions have been written for Ubuntu 13.04, but originally I also tried it on 12.10, so it might work for earlier versions as well.

First of all, we need some way of connecting to the Launchpad, program its flash memory, execute and break programs, step through a running program, etc. This is done using a debugger, and for MSP430 it is provided in the package mspdebug. This debugger contains some basic hardware controlling functions and assembly stepping, but it can also be used as a backend to GDB if we want to have more advanced debugging facilities, and also have the connection to our C source code. GDB itself is provided in the package gdb-msp430. Finally, we will want to compile C source code using GCC. A version of GCC that suits the MSP430 is provided in the package gcc-msp430. So, let’s install these packages!

$ sudo apt-get install mspdebug gdb-msp430 gcc-msp430

Nice and simple! If we do dpkg -L on these packages in turn, we see that gcc-msp430 contains C runtime libraries and (at least somewhat surprisingly for me) some more advanced math routines. Besides our selected packages, we also get some additional package dependencies installed automatically. Package binutils-msp430 contains utilities for handling MSP430 object files, together with assembler, linker and top-level linker scripts that we will be looking at in a later tutorial. Package msp430-libc contains an implementation of most of the functions of a standard libc, along with relevant standard header files. Finally, package msp430mcu contains include files and lower-level linker scripts for all the different MSP430 versions.

Now, we should be ready to try connecting to the Launchpad, so let’s go ahead and plug in the USB cable from the Launchpad. Typing the command

$ dmesg

we should see some log events about a new full-speed USB device Texas Instruments MSP-FET430UIF having been found. Despite the fact that it presents itself as FET430UIF, when connecting to the Launchpad we should actually use the rf2500 driver. (I don’t know the details about the differences.)

$ mspdebug rf2500

If all goes well, mspdebug starts up, connects to the Launchpad, and acknowledges that it has found a device to communicate with. For my version of the Launchpad, this is

Device ID: 0x2553
Device: MSP430G2553

We can now play around with the debugger a little bit. Try for example the commands reset, run, and then break the execution with Ctrl-C to see a dump of the sixteen MSP430 registers and the disassembled code that was running at the time of break. When we’re done, the exit command terminates the debug session.


MSP430 Launchpad development using GNU tools

I bought myself an MSP430 Launchpad development board from Texas Instrument. Upon receiving it I started to investigate the available tools for software development. Sure, we could use a free version of IAR Embedded Workbench from TI, but that would limits us to 4 kB code size and force us to use Windows. Or we could the Eclipse route and use Code Composer Studio from TI, which also runs on Linux, but the free version is limited to 16 kB code size. This is not a problem for the MSP 430 chips that are included with the Launchpad, but surely it would be more interesting to use the GNU toolset and other free tools to do the development?

After doing some web searches, it seems that most of the tutorials in this area are quite old. There is a lot of stuff about how to compile your MSP430-gcc, but nowadays we have the tools we need included in a stock Ubuntu distribution, so there is no need to spend time on that. So I will try to describe how get up and running with Ubuntu, gcc and gas. In the upcoming blog posts, we will visit the following topics:

  • Installing the software on Ubuntu 13-04
  • Programming the MSP430 in C using GCC
  • Programming the MSP430 in pure assembler using GAS