“Bare Metal” MSP430 Programming: Learning About a New Microcontroller

Most of the embedded programming that I’ve written about so far has focused on the STM32 family of ARM microcontrollers produced by ST Microelectronics. Those are a reasonable starting point for learning about microcontrollers, because they have a solid suite of open-source development tools, a decade-long history of popular use, and affordable hardware development tools which let you get started for less than $20.

But now that platforms like Arduino have become popular and presumably profitable, more vendors are getting on board with providing affordable “DIY” development tools. So while I couldn’t find any cheap and widely-available USB debuggers for TI’s MSP430 core, the “Launchpad” boards that they sell each include an on-board debugger which they say can talk to most MSP430 chips through a two-wire interface similar to the “Serial-Wire Debug” protocol used by a number of Mobile ARM cores including the STM32.

Like the Arduino Uno, some Launchpad boards use DIP chips which you can remove and plug into a breadboard once they have been programmed.

So let’s learn how to write bare-metal programs for the MSP430! This will be easier than bootstrapping a build system for the STM32, because TI opted to design a special-purpose 16-bit RISC core for these chips instead of buying a cookie-cutter core from ARM. That means that the MSP430-GCC toolchain can include ‘glue’ code like linker scripts and vector tables for every MSP430 chip ever made, and we will not need to write our own. There are also fewer steps involved in setting up clocks and peripherals, so this is a comparatively easy platform to develop on. And as usual, this tutorial’s code is on Github.

The MSP430

First, a little bit of background on the MSP430. In a nutshell, it is very similar to the original ‘Arduino’ AVR cores but with lower power consumption and 16-bit buses instead of 8-bit ones – there is even a port of the Processing IDE called Energia that targets these chips. It is still significantly slower than almost all ARM Cortex-M cores, but it can use much less power to run simple programs.

This tutorial will use an affordable ‘Launchpad’ board sod by TI. They cost about the same as ST’s ‘Nucleo’ boards – a little less than $11 – but the exact version you get will depend on when it was made. I’ll use their MSP430G2553 board, which is currently sold as the MSP-EXP430G2ET. This code will also work with an older MSP-EXP430G2 board though, and it’s pretty easy to spot the difference:

Left: the “old” board. Right: the “new” board. It’s too bad that QFP chips seem to be going out of style.

The Toolchain

It’s always nice to use open-source tools if you want to learn about how something works at a low level, and fortunately these MSP430 chips are supported by GCC and an open-source programmer/debugger. The MSPDebug utility written by dlbeer et al is very similar to the STLink utility from previous tutorials written by texane et al. It can flash binary images to MSP430 chips, and connect them to GDB sessions. Here are links to the MSP430-GCC and MSPDebug tools that you’ll need to install:

Be aware, however, that your package manager may have older versions of these utilities. As of the time of writing, it looks like the default Ubuntu repositories have a version of mspdebug which does not support the newer MSP430 Launchpad boards which you can buy today, and a version of gcc which does not support the newest FRAM-based chips. So you may need to manually install the most recent versions depending on which board you are using.

Blinking an LED

Like I mentioned above, the MSP430 GCC toolchain can automagically provide ‘boot code’ like linker scripts, vector tables, and startup assembly. Even better, it includes device header files for the chips, so we don’t need to go find those on the manufacturer’s site. That means that we can jump straight to a C main method, and this entire ‘Hello World’ project can fit in one brief main.c file (available on Github). The MSP430-specific lines are highlighted:

The msp430.h header file is included with the toolchain, and it is similar to the STM32 device header files. It defines almost-legible names for the chip’s register addresses and settings; P1DIR is not exactly easy to read, but it is much nicer than (volatile uint16_t *)0x0022.

The WDTCTL register controls the chip’s watchdog timer. Most modern microcontrollers have a watchdog timer, which automatically resets the chip if it is not periodically assured that everything is working. Most modern microcontrollers also leave it turned off when the chip resets, but the MSP430 is optimized for low power usage, and there are probably a few reasons why this feature is enabled by default. Anyways, our simple program does not use the watchdog timer, so we should turn it off. The WDTPW bits are a protective ‘password’ which must be included in all writes to the ‘watchdog control’ register; if you’re interested, see the ‘Watchdog Timer+’ section of the reference manual for more details.

The P1DIR register sets the ‘direction’ of Port 1 GPIO pins, between ‘Input’ (0) and ‘Output’ (1). The MSP430’s output mode is push-pull only, but their I2C peripherals can set an open-drain mode and there may be ways to simulate that behavior.

And the P1OUT register is similar to the STM32 ODR registers; it sets ‘Output’ pins to a high or low logic level. The Launchpad boards have LEDs on pins P1.0 and P1.6, so we blink the LEDs by toggling BIT0 and BIT6 in P1OUT.

Compiling and Flashing

Since there’s only one C file, we can compile it with a single command:

msp430-gcc -g -Os -Wall -mmcu=msp430g2553 -I./ -c main.c -o main.o

And a similar command links the single object file into a binary:

msp430-gcc main.o -g -mmcu=msp430g2553 -o main.elf

Finally, we can flash the program using mspdebug. This command will depend on which board you are using. For the “old” version, ask for an rf2500 interface:

sudo mspdebug rf2500 'erase' 'load main.elf' 'exit'

For the “new” version, use a tilib interface. If you get an error, you may need to build and install the msp430.so library. You might also be prompted to update your debugger’s firmware version, which you should do if and only if you are using a version of mspdebug >= 0.25 (maybe 0.24 too?):

sudo mspdebug tilib 'erase' 'load main.elf' 'exit'

The mspdebug utility acts as a REPL, but you can also pass it a series of commands to run in series. Here it erases the chip, programs it with main.elf, and then exits the utility. And if you don’t want to use sudo, the tool’s FAQ talks about how to set up USB permissions.

After the mspdebug command finishes, the red and green LEDs near the bottom of the Launchpad board should start to blink on and off alternatively.

The ‘P1.0’ and ‘P1.6’ LEDs should both blink on and off.

Conclusions

I haven’t done much with the MSP430 yet, but it looks like a fun chip to use. It also looks like an excellent choice for battery-powered devices because of the potential for very low power usage – it sounds like they can use less than 5 microwatts in some of its low-power standby modes at 3V.

I’m hoping to follow up on this post with a guide on using these Launchpad boards’ built-in debuggers to program a custom MSP430 board, but I won’t know if that actually works until the PCBs arrive. I’d also like to write more about low-power design, but I should probably learn more about it first.

Related posts:

Evaluation boards are great, but eventually you’ll want to make a design which needs to fit in a smaller space, or which uses a type of chip that doesn’t have a cheap board available. When that happens, you’ll often want to design a PCB. And it seems like most microcontrollers have similar basic hardware requirements; decoupling capacitors on the power pins, maybe a pull-up resistor and filtering capacitor on the reset pin, and a few pins which are used for debugging and programming. The MSP430 is no different, although it does have a few small quirks to be aware of.

And while I haven’t found a cheap dedicated USB device for programming MSP430 chips, you can use the debuggers built into TI’s Launchpad boards to program and debug a custom board using their “Spy-Bi-Wire” protocol. So in this tutorial, I’ll go over a basic circuit design for an MSP430FR2111 chip. It comes in a TSSOP-16 package with 3.75KB of FRAM and no Flash memory.

A simple example MSP430FR2111 breakout board design.

I’ll also go over the differences between programming a ‘pulsing LED’ example for the MSP430FR2111 and the MSP430G2553 that we used in the last two examples, as well as how to connect a Launchpad board’s debugger to upload programs to the custom board. So let’s get started!

Recently, I wrote about setting up a basic ‘hello, world’ program for an MSP430 microcontroller. These chips look like they are designed to make low-power designs easy to code, so it seems like a good idea to start learning about their low-power sleep modes. TI claims that, at 3V and a 1MHz core clock speed, an MSP430x2xx will consume about 300μA while running, 55μA in “low-power mode 0”, and as little as 0.1μA in “low-power mode 4”. But you may have difficulty reaching those figures on a Launchpad board because of how the circuit is laid out.

You can see section 2.3 of the reference manual for more details on these sleep modes, but the most important thing to know is that different low-power modes can selectively disable the core CPU, system clocks, and peripherals on the chip. Some clocks and peripherals remain active in some low-power modes. For example, the chip’s timers can continue to run while the CPU is off as long as the system clock they are connected to is still active.

So in this tutorial, we’ll walk through pulsing a common-cathode RGB LED through various colors using the MSP430’s timers to generate PWM signals while the chip rests in LPM0 sleep mode. We need to set up the timers and attach an interrupt to periodically change the PWM duty cycles, but once that is done we can turn off the CPU. The timer interrupt will periodically wake it up, and the chip will automatically go back to sleep after the interrupt handler returns.

“Common-Cathode” LEDs let you control a red, green, and blue LED individually using PWM signals. Each LED is connected to the same cathode (‘ground’).

This post’s Github repository contains two projects; one which dims and brightens a single on-board LED using PWM, and one which uses a timer interrupt to pulse each color in a common-cathode RGB LED while putting the device to sleep when it is not active.

Like many of us, I’ve been stuck indoors without much to do for the past month or so. Unfortunately, I’m also in the process of moving, so I don’t know anyone in the local area and most of my ‘maker’ equipment is in storage. But there’s not much point in sulking for N months straight, so I’ve been looking at this as an opportunity to learn about designing and implementing FPGA circuits.

I tried getting into Verilog a little while ago, but that didn’t go too well. I did manage to write a simple WS2812B “NeoPixel” driver, but it was clunky and I got bored soon after. In my defense, Verilog and VHDL are not exactly user-friendly or easy to learn. They can do amazing things in the hands of people who know how to use them, but they also have a steep learning curve.

Luckily for us novices, open-source FPGA development tools have advanced in leaps and bounds over the past few years. The yosys and nextpnr projects have provided free and (mostly) vendor-agnostic tools to build designs for real hardware. And a handful of high-level code generators have also emerged to do the heavy lifting of generating Verilog or VHDL code from more user-friendly languages. Examples of those include the SpinalHDL Scala libraries, and the nMigen Python libraries which I’ll be talking about in this post.

I’ve been using nMigen to write a simple RISC-V microcontroller over the past couple of months, mostly as a learning exercise. But I also like the idea of using an open-source MCU for smaller projects where I would currently use something like an STM32 or MSP430. And most importantly, I really want some dedicated peripherals for driving cheap addressable “NeoPixel” LEDs; I’m tired of needing to mis-use a SPI peripheral or write carefully-timed assembly code which cannot run while interrupts are active.

But that will have to wait for a follow-up post; for now, I’m going to talk about some simpler tasks to introduce nMigen. In this post, we will learn how to read “program data” from the SPI Flash chip on an iCE40 FPGA board, and how to use that data to light up the on-board LEDs in programmable patterns.

The LEDs on these boards are very bright, because you’re supposed to use PWM to drive them.

The target hardware will be an iCE40UP5K-SG48 chip, but nMigen is cross-platform so it should be easy to adapt this code for other FPGAs. If you want to follow along, you can find a 48-pin iCE40UP5K on an $8-20 “Upduino” board or a $50 Lattice evaluation board. If you get an “Upduino”, be careful not to mis-configure the SPI Flash pins; theoretically, you could effectively brick the board if you made it impossible to communicate with the Flash chip. The Lattice evaluation board has jumpers which you could unplug to recover if that happens, but I don’t think that the code presented here should cause those sorts of problems. I haven’t managed to brick anything yet, knock on wood…

Be aware that the Upduino v1 board is cheaper because it does not include the FT2232 USB/SPI chip which the toolchain expects to communicate with, so if you decide to use that option, you’ll need to know how to manually write a binary file to SPI Flash in lieu of the iceprog commands listed later in this post.