TinyOS on the MSP430 Launchpads

10/1/2014 – Updated compilation instruction for the MSP Debug Stack

My semester project for CS5204 Operating Systems was to get TinyOS running on some unsupported MSP430 chips. While there are some resources out on the interwebs on how to get TinyOS running on specific hardware platforms, these platforms are designed with hardware for a specific use cases (ex. telos/micaz). What I wanted to do was to get TinyOS running on a generic development platform, or specifically on the TI Launchpads. There are two versions of the Launchpads in circulation: a value line that uses the MSP430G2xxx line of microcontrollers and a higher end board that uses the MSP430F5529 microcontroller. Here I’ll detail the process of setting up a TinyOS programming environment for both TI Launchpad platforms. I’ll also give a brief overview of TinyOS’s architecture.

TinyOS Primer

First of all, what is TinyOS and why use it? From its FAQ: “TinyOS is an open-source operating system designed for low-power wireless devices, such a sensor networks, ubiquitous computing, personal area networks, smart buildings and smart meters. TinyOS provides useful software abstractions of the underlying device hardware: for example, TinyOS can present a flash storage chip, which has blocks and sectors with certain erase/write properties, as a simple abstraction of a circular log. Providing useful, well-designed and heavily tested software abstractions greatly simplifies the job of application and system developers. TinyOS is especially useful for microcontroller-based devices that have sensors and/or networking capabilities. It’s been designed for very resource-constrained devices, such as microcontrollers with a few kB of RAM and a few tens of kB of code space. It’s also been designed for devices that need to be very low power.”

Unlike platforms such as the Arduino, TinyOS was designed with a two major features in mind: low power operation and extensive support for networking protocols. To achieve these design goals, the core of TinyOS is completely non-blocking. As such, everything that runs on the processor originates as asynchronous tasks that can call callback functions upon completion. While the processor is idle, the OS automatically enters the lowest possible sleep state available. Because of this non-blocking design, programming for TinyOS can take a while to get used to.

Abstractions are extensively used in TinyOS to provide code re-usability and portability between various platforms and microcontrollers. Programs are built out of software components, some of which present hardware abstractions while others abstract higher level concepts such as networking protocols, etc. These components are then interconnected through the use of pre-defined interfaces. Combined, interfaces and components allows abstractions of common services, such as packet communication, routing, sensing, actuation, and storage.

Since TinyOS was originally designed for sensor networks, there also exists extensive support for networking protocols such as FTSP and CTP, along with various algorithms such as Trickle and Deluge. In terms of hardware, TinyOS has built in support for a variety of radio chips including the ChipCon CC1000, CC2420, CC2500, Infineon TDA5250, Atmel RF212, Atmel RF230, Semtech XE1205, and more. In order to support these abstractions, the base code of TinyOS is programmed using nesC, a new(er) C dialect that is being developed alongside of TinyOS.

A sample Led component written in nesC is shown below. As you may guess from the code, this component uses the interface Gpio and provides and implements the interface LedControl. We’ll go into more details on how these abstractions are structured and organised later on when we examine the basic Blink program.

Installing TinyOS

Here I’ll list the steps required in creating a developing environment for TinyOS on the TI Launchpads. For reference, I used a new installation of Linux Mint 15 x64 (Ubuntu 13.04) in a virtual machine. After fully updating the system, there are two ways of setting up the development environment. The first one is an automated process that uses a setup script bundled with the third party extension that we are going to be using. The second method involves installing the development tools individually.

Automated Installation

To install the msp430 toolchain, we can grab it from the main Ubuntu repository:

To automatically install TinyOS and the extension, follow the instructions here. For the lazy, run the following:

Note that to successfully run this script, you’ll need to install the following packages:

The script is set up to install TinyOS a to a directory specified in scripts-tinyos-msp430/config.subr. TinyOS is set to install to /opt/tinyos by default so we’ll go ahead and use it as is. Binary files for nesC are found in /opt/tinyos/bin. If you get a stow error at the end of the first script, you’ll need to unstow then restow the directories:

Afterwards, both TinyOS and the third party extension will be combined by stow into /opt/tinyos/root. Before running any programs in the toolchain, run the following to set up required environmental variables (or put it in your .bashrc):

If the steps above complete successfully, you should be good to go.

Manual Installation

Alternatively you can build nesC and TinyOS for other platforms by following the instructions here: Installing TinyOS. If you do so using this method, you’ll have to download the third party extension separately and manually create the stow hierarchy.

Quick primer on the Stow utility

Stow is a utility for combining folders through the use of symbolic links. The program works by linking a number of source folders into a target folder. The target folder then contains all the files and folders that are located in each of the source folders. Overlapping files with identical names will cause the stow program to error out. Note that while you can overlap folders, any files that are created in the target folder MUST be in a directory that was originally unique to any of the source folders. Otherwise the utility doesn’t know which source folder the file belongs to!

To combine source folders into a target folder: stow -S -t <target folder> <source folder>
To separate source folders from the target folder: stow -D -t <target folder> <source folder>
Refer to the man pages for more information.

Programming a Launchpad

Programming for the value line launchpad with the msp430g2553 microcontroller is relatively straightforward. In Linux, you simply compile your program into a binary file before running mspdebug to transfer the binary file to the microcontroller. The emulator on this board is called the MSP-FET430 Flash Emulation Tool (FET) and provides a serial connection to a computer typically over /dev/ttyACM0 or /dev/ttyACM1. When calling the compiler, you typically specify the device so that it includes the correct device header file. The mspdebug program can be used for not only programming but also to step through the program and view register contents.

In Linux, you may have to explicitly set permissions to allow mspdebug to allow access to the serial port. To do so add the following line to /etc/udev/rules.d/46-TI_launchpad.rules :

Programming for the higher end launchpad though required a bit more set up as it uses a different emulator. Called the EZ-FET, this emulator requires a unprovided DLL for interfacing. Under Windows, this file (MSP430.DLL) can be found here: MSP Debug Stack. For Linux however, we’re going to have to compile one for our system. Download the source code from here: MSPDS Open Source Package and extract it into a folder somewhere. If you try to compile it straight away though, it won’t work as it’ll complain with an hidapi error. To fix this, we’re going to have to compile the hidapi library required for MSPDS. To do so, we need to install some extra libraries:

Once the libraries are installed, first download and extract hidapi-0.7.0, then modify hidapi-0.7.0/linux/Makefile and add the flags -pthread and -fPIC to the compiler flags (CFLAGS/CXXFLAGS). Afterwards run make to build the required hidapi library. Once the library is compiled, copy hidapi-0.7.0/hidapi/hidapi.h to ThirdParty/include and hidapi-0.7.0/linux/hid-libusb.o to ThirdParty/lib in the extracted MSP Debug Stack directory. Once these two files are copied, run the following to build and install the library file:

Once this is done, you can transfer the generated binary file to the board by calling the following:

Directory Structure

TinyOS Directory The directory structure of TinyOS is shown on the right. If you download and extract the latest version of TinyOS (2.1.2 as of this post), you’ll see that support for many chips and platforms already exists. Not supported however, are the MSP430G2274 and MSP430F5529 chips that are used in the TI Launchpads. We’ll get to it later on, but we’re going to need to add support in for these chips.

The organizational structure of TinyOS is interesting in that it separates the chips from the platforms. Each chip is defined separately as package of components, and a platform is structured to include a number of chips. TinyOS uses the make utility to organize, compile, and program a platform. To make it easier on the end user, an <uC>.rules file is specified in /tos/support/make for each microcontroller family along with an <X>.target file for each platform that points to its corresponding <uC>.rules file. The user then only needs to execute make <X> install to compile and program the <X> platform.

Aside from the <uC>.rules and <X>.target files, each platform also has a few files that must exist in platform <X>‘s directory. These mandatory files include .platform which defines what chips are part of the platform, hardware.h which specifies extraneous defines, PlatformC.nc which is the top-level initialization component, and McuSleepC.nc which implement the power management features of the microcontroller.

Components and Interfaces

The file naming convention in TinyOS can be a bit hard to grasp. A typical component can typically have anywhere from two to four files: Foo.nc specifies the interface, Foo.h is the header file, FooC.nc is the public module, and FooP.nc is the private module. The interface provides a list of commands and events, where the commands are callable functions and events are callback functions. The header file is used to specify a few hard-coded compile time defines. The public module is a component that links together other components (through interfaces) and its own functionality (in its private module). To get a better understanding, lets look at the basic Blink program.

Sample Program: Blink

The blink program has two high level (user) files: BlinkAppC.nc and BlinkC.nc.

As the configuration for the top level module, BlinkAppC does not use or implement any interfaces. Instead it simply provides the instructions to connect a number of sub-components together. At the start of the implementation section, the configuration declares all the components that it uses. The components on the first line are singletons, while the timers are generic components which allow for multiple instances. The latter part of the configuration specifies how the components are interconnected. For example, the BlinkC module uses the Boot interface which calls the callback booted() after the device is started. It is up to the module that uses this interface to implement the callback function. This interface is implemented by MainC, and nesC allows for the interconnection to be defined using an arrow pointing from the interface to the implementation. By default nesC tries to bind to the interface with the same name, thus line 7 could be replaced by line 8 with no change in meaning.

BlinkC is a private module that only interacts with other components through its declared interfaces. In this case, BlinkC uses two generic timers, the Leds component, and the Boot component. Once the device is started, the main event handler will call the callback Boot.booted(), which is implemented by this module. In this initialization code, BlinkC can use the interfaces without needing to know how the interfaces are implemented in the underlying platform. It simply knows though the interface definition that it can provide a callback function that gets executed once the device is booted. This abstraction through the use of components is what gives TinyOS its power and flexibility. Aside from the booted() callback, this module also implements two other callbacks, one for each timer. Within each timer callback, the module simply calls a function through the Leds interface.

For a more in-depth/alternate explanation of the Blink program, refer to the TinyOS tutorials here.

Here is a component hierarchy map that I made for the basic Blink program. As this program is pretty basic, there are only three main parts: required processor and TinyOS components; LED and general I/O components; and timer abstractions. Adding in other complex peripherals such as the UCSI (Universal Serial Communication Interface) would easily double if not triple the size of this map.

TinyOS Blink Abstractions

As it can be seen from the diagram, the Blink program calls the Boot interface that is implemented by RealMainP. This module then calls the actual platform configuration PlatformC which we’ll examine in the following section.

Blink on the Msp430G2553 without TinyOS

How would this code look if we didn’t implement it through TinyOS? As you can see from the code below, TinyOS abstracts away pretty much everything. Through such abstractions, the code becomes much easier to understand as long as the user is familiar with nesC and the abstraction structure.

Platform Common Files

To further our understanding of how things are implemented, we’ll take a look at some of the files that make up the platform. Due to the abstractions, almost all the underlying components for peripherals are identical across a given microcontroller family. As such, many of these files will remain unchanged when we create new platform that utilizes a chip that is part of the family. We’ll take a look at some of the higher level initialization components located in /opt/tinyos/root/tos/platform/msp-common.

Here we have our top-level component for initializing the msp430 platform. All that it does is link together the platform’s private module PlatformP.nc with the clock configuration component. It also provides an Init interface for the Blink program to call.

The list of possible interfaces that components can use or provide are found in /opt/tinyos/root/tos/interfaces and /opt/tinyos/root/tos/lib/. Here is the Init interface, which simply provides a callable function for initialization.

The private module PlatformP.nc is where the initialization functions are actually implemented. In this case, when another component calls this component’s Init, it executes the initialization function for both the clock as well as the leds abstraction.

The McuSleepC.nc is another important file, as it provides the power management functionality for the microcontroller. While most microcontrollers in the same family use the same oscillator configurations, the registers and sleep states may differ between different families so one should verify that the information in this file is correct.

Platform Specific Files

Aside from the common components, there are a few extra files that define each platform. For each platform specified in /opt/tinyos/root/tos/platforms, a few files must exist for TinyOS to know where to pull files from when compiling.

The .platform file provides the nesC compiler a list of locations from where to look for components and interfaces. Starting from the top, it looks first in the platform folder before going into other folders that hold common components. As such you can always put a component in the platform folder to overwrite any of the common components. Components for the scheduler are also specified here but you’ll rarely be changing them.

The hardware.h file for each platform serves as a location for the user to put extra defines. Such defines can be used for things such as specifying hardware revisions or enabling/disabling hardware functionality (such as I2C master/slave).

A platform target file must also exist in /opt/tinyos/root/support/make for each platform. This target serves to define the platform, the microcontroller used within the platform, any extra compiler flags, and the program and driver used in programming the microcontroller. A call to TOSMake_include_platform, msp indicates to make that we want it to call msp.rules under /opt/tinyos/root/support/make/msp/ which contains the actual target for producing the binaries for the msp430 line of microcontrollers.

Running Blink on the Value Line Launchpad

Since the msp430g2553 platform is already implemented through TinyOS and the installed extension, we can run the Blink program on the board without having to add or change much of the underlying code. We will have to change some however, as the launchpad board only has two LEDs and the msp430g2553 microcontroller uses 16-bit timers. Note that the launchpad board MUST have a 32.768kHz crystal attached to the X1 oscillator pins. TimerA uses this oscillator for its operation.

First of all we need to change PlatformLed.h in /opt/tinyos/root/tos/platforms/msp430-common/ to support more than one output LED. Within the header file, change the code to the following to define the second LED on pin 1.6:

Then in BlinkAppC.nc, remove the Timer2 declaration and bindings and add the following above the configuration to let the compiler know that this device is running on the value line launchpad board:

Finally, in BlinkC.nc, remove the references to Timer2. Once you have done this, you can program the board:

If everything goes well, you should see the red LED toggle four times a second and the green LED twice every second. If you truly wanted to match the hardware, you should change TimerMilliC() to Timer16MilliC() in BlinkAppC.nc, Timer<TMilli> to Timer16<TMilli> in BlinkC.nc, and the include from “Timer.h” to “Timer16.h” in BlinkC.nc. This is due to the hardware timers on the device being 16-bits in length, rather than the standard 8-bits. The normal 8-bit timer abstractions still work however, due to the way TinyOS is structured.

Creating the MSP430F5529 Platform

Now that we’ve gone over the basics for TinyOS, lets create a new platform for the MSP430F5529 launchpad. While we are still going to be using the library extension, it would make things easier if we used stow to isolate the TinyOS code base, the extension, and the code that we’re going to be adding. First download the file here and run the following to extract it into /opt/tinyos/sources/:

There should now be a tinyos-msp430-large folder in /opt/tinyos/sources, which should have two folders (support and tos) in it. Then run the following to combine the three folders in /opt/tinyos/sources into /opt/tinyos/root:

Before we try programming the new device, lets go over some of the files that I’ve added.

In /opt/tinyos/sources/tinyos-msp430-large/tos/chips, I created a new msp430-large folder that puts in support for the MSP430F5xxx family of microcontrollers. Please note that the components in this folder are incomplete and may not work with all features and peripherals on the device. The only components that I’ve verified to be working are McuSleepC.nc as well as the basic timer code.

In /opt/tinyos/sources/tinyos-msp430-large/tos/platforms, I created a new msp430f5529 platform for the higher end device. This platform implements a different .platform file that tries to grab components from the msp430-large folder rather than from the msp430-small folder of the other devices.

In /opt/tinyos/sources/tinyos-msp430-large/support/make, I created a msp430f5529.target file so that make knows how to run the compiler. In addition to the change in the targeted device, the mspdebug driver is also specified so that the utility calls the right one (tilib) for the emulator rather than the default (rf2500).

Running Blink on the High End Launchpad

Before we can interface to the LEDs, we need to change PlatformLed.h to support the new board. Within the header file in /opt/tinyos/root/tos/platforms/msp430-common/, change the code to define the second LED on pin 4.7:

Once we’ve done this, we should be able to program the Blink program onto the launchpad board:

Note that due to the layers of abstractions, we didn’t have to change anything in the code prior to running the program on a different device.

Blink on the Msp430F5529 without TinyOS

As a final note, lets look at what the Blink program looks like on the higher end launchpad if TinyOS wasn’t used.

Other Resources

TinyOS wiki: http://tinyos.stanford.edu/tinyos-wiki/index.php/Main_Page
List of TEPs: http://tinyos.stanford.edu/tinyos-wiki/index.php/TEPs
TinyOS Tutorials: http://tinyos.stanford.edu/tinyos-wiki/index.php/TinyOS_Tutorials
TinyOS Programming Manual: http://csl.stanford.edu/~pal/pubs/tos-programming-web.pdf