Published on (
 See this if you're having trouble printing code examples

Black Box with a View

by George Belotsky

What is an embedded system? With embedded Linux (and Windows) getting plenty of press coverage, it appears that the embedded environment is much like an ordinary PC. In fact, most embedded systems do not run Linux or Windows. Instead, the microcontroller dominates the field. These single-chip devices resemble an Apple II or a Commodore 64--the personal computers of 25 years ago.

A desktop-class CPU and a microcontroller
Figure 1. Pin-side views of an Intel 486 DX CPU (left) and a Texas Instruments MSP430F149 microcontroller

Consider Figure 1. The 486 is the sort of device that could run Linux in an embedded environment, while the MSP430 is a typical modern microcontroller. In particular, note the far smaller number of pins on the MSP430--a rough indication of the relative complexity of the two devices.

Like early personal computers, traditional microcontroller applications are tiny islands of functionality, with little connectivity to the outside world. Consider such devices as a microwave oven, a telephone answering machine, and a wristwatch. Each system has its own user interface, and each performs its own highly specialized task.

It is not possible, for example, to turn off your microwave oven remotely with the wristwatch by using the answering machine as a telephone communications gateway. With the emergence of initiatives such as the Cambridge-MIT Institute's Pervasive Computing, however, such capabilities could become common.

The goal of Pervasive Computing is to create a network of collaborating machines, possibly with hundreds of devices per user. These collaborating groups of connected embedded systems will likely be the next mainstream computing platform. The ordinary PC will then follow its mainframe predecessor to become a specialized tool (albeit still an important one) for a relatively small set of core applications.

While the age of Pervasive Computing has not yet arrived, much of the necessary technology is available today. Powerful microcontrollers (some of which feature very low power consumption) are widespread. You can even purchase inexpensive development kits with Ethernet hardware already onboard.

An embedded system designed for connectivity is like a precisely defined window put on the traditional black box device. Sophisticated diagnostics, advanced interaction with the user, and meaningful network simulations (supported by actual hardware) all become possible.

The purpose of this series of articles (continued in Black Box with a View, part two) is to help you develop connected embedded systems using current technology. Communication between the embedded device and a standard PC is particularly useful, due to the current prevalence of as well as significant computing power of the latter. In the Pervasive Computing future, interaction with PC-type hardware will also continue to be important, because such systems will play the role of gateways and control workstations for networks of embedded devices.

The Nature of Embedded Systems

It is important to understand the nature of embedded systems before starting your own project. If you have little experience with such systems, this article will provide a foundation. The next article will build on the information presented here, by covering several key embedded development techniques. Advanced readers can use these two articles as a review.

Embedded software is the focus of discussion here, so this article covers everything you need to start quickly. You will not have to build any hardware in order to follow the examples in this series of articles. Of course, you will need at least some knowledge of electronics and a basic set of tools (a digital multimeter, a soldering iron, and so on) in order to complete an actual project.

In the microcontroller world, assembly language and C still dominate. C++ is also popular but is not as well supported as C. This series therefore uses the C language for the examples. The resulting code is quite easy to read, although you should have at least some prior knowledge of the language. You should also have a good C reference book (such as C: A Reference Manual) that covers the complex details of the language and its implementations. The reference book is not necessary to follow these articles, but it will be helpful for your own projects.

In addition, keep in mind that operating system support is minimal in microcontroller-based devices. Any serious work requires direct interaction with the hardware. In fact, embedded software often runs with no operating system at all--as the examples in this series illustrate. If you have experience with programming under Linux or Windows, embedded development is much more like writing a device driver than a typical application program in those environments.

Despite their many similarities to early personal computers, microcontrollers are not designed for general-purpose computing as we know it today. In particular, the balance of storage capacity and processing power is very different in embedded applications. For example, the Texas Instruments (TI) MSP430 microcontroller (PDF file) shown in Figure 1 can run at 8MHz but has a maximum of 2K of RAM and 60K of flash memory for storing code as well as static data. Models with 10K or 5K of RAM are available, but only with smaller amounts of flash memory. One MSP430 variant has just 128 bytes of RAM and 1K of flash. In contrast, the Commodore 64 ran at 1MHz but had 64K of RAM, 20K of ROM, and several secondary storage options--including a floppy disk drive with 170K per disk.

Of course, secondary storage solutions (such as flash memory devices) are also available for embedded systems. Unfortunately, the constraints of cost, power consumption, and physical size are often very stringent in embedded applications. In addition, many devices need to survive shock, vibration, and other extreme environmental conditions. Thus, the multigigabyte hard disk, so common in the PC world, is rarely suitable for embedded projects. As the result, microcontroller software design often emphasizes efficient memory use over processing speed--the exact opposite of general PC-based development.

Choosing a Platform

The modern PC landscape consists of relatively few variations in system architecture. In contrast, there are significant differences between many microcontrollers. Traditionally, these were 8-bit devices, but 16-bit and even some 32-bit components are now common. The diversity of embedded applications, combined with often severe application-specific limits, require a corresponding diversity in the choice of microcontrollers.

For this series of articles, several key considerations drove the platform selection:

The TI MSP430 microcontroller matches these criteria very well. Of course, many alternatives are possible (the Atmel AVR and the ARM7, for example). If your budget allows, order several development boards based on different microcontrollers so that you can experiment before making the final choice for a project.

The MSP430 is an 8MHz, 16-bit device with a RISC core and an orthogonal instruction set. These features allow very efficient object code generation by a compiler. Assembly language programming--often required on less compiler-friendly architectures--is used far less frequently on the MSP430. Nevertheless, the MSP430 still is very much a microcontroller. The techniques presented in this series of articles would not be out of place on an Intel 8051, designed in the 1980s and still very popular.

Several proprietary C compilers are available for the MSP430. These articles, however, use the open source mspgcc. Mspgcc is a port of the famous GNU Compiler Collection (GCC) compiler suite to the MSP430. Appendix A gives directions for installing mspgcc under both Windows and Linux.

Mspgcc provides a complete set of open source tools, including support for symbolic debugging. Note, however, that debuggers are often harmful in the embedded environment. The next article will discuss the subtle problems that symbolic debuggers can introduce.

The development board used for these articles is the Olimex easyWeb2. Compiled programs are loaded onto the board via the Olimex JTAG adapter. Olimex ships internationally. The author purchased the easyWeb2 and the JTAG adapter through the Olimex North American Distributor, Spark Fun Electronics.

You will also need a DC power supply to run the easyWeb2. The familiar AC adapter ("power brick") fulfills this need simply and inexpensively. Spark Fun will sell you a suitable adapter for a small additional cost.

Note that the easyWeb2 regulates its power input (see the schematic), so do not be surprised if different distributors offer adapters with different ratings. This also means that you may already have an adapter that will work with the easyWeb2. If in doubt, however, it is much safer to purchase the right power supply when you buy your board.

See Appendix B for information on how to set up the hardware.

Picture of the easyWeb2 development board
Figure 2. The easyWeb2 development board

In Figure 2, note the JTAG adapter ribbon cable at the top left. The red stripe on the cable designates pin 1. Make sure that you match the stripe to the actual pin 1 of the JTAG connector. A label on the board beside this connector designates pin 1. The plug for the AC adapter is also visible near the top right corner of the board.

The easyWeb2 includes input switches, relay-driven outputs, a small LCD screen, and an RS232 serial port. There's also an Ethernet port (along with the required supporting hardware) for developing embedded network devices that can attach directly to the LAN.

Support for serial communication is particularly important for the later articles in this series. RS232 and RS485 I/O is simple, but surprisingly capable. It remains the prevalent method for embedded system connectivity today.

Of course, many other MSP430-based boards are available. You can even build one yourself (perhaps using a development kit as a starting point). If you want to use something other than the easyWeb2, the following requirements should be sufficient:

The examples in this series use JTAG to upload the firmware to the target. If your hardware supports the serial bootloader, using it is quite similar to using JTAG. The serial bootloader is slower and does not allow symbolic debugging, but it is more reliable. The mspgcc project includes tools (pyJTAG and pyBSL) for both methods.

Hello (Embedded) World

When you start programming using an unfamiliar language or operating system, it is very helpful to write a Hello World program. Such simple programs are the first step in understanding the new environment.

For embedded systems, however, a Hello World program has a critical additional role. This role is to verify that the entire development tool chain--especially the target hardware--works. The process of running a program on an embedded platform is quite complex. You write the code on a host machine (typically a PC), compile it with a cross-compiler, and then upload the result onto the target through an interface (such as the JTAG adapter). Numerous problems can arise at each step.

For example, microcontrollers, even in the same family, often differ dramatically from each other. If you give the wrong options to the cross-compiler, or assume the existence of certain hardware features when writing your program, it is quite possible that the target device will be unable to execute the resulting object code.

The target hardware itself is often an early prototype; in the embedded world, it is rare for the electronics design to be completed before software development starts. Hardware errors and component failures--very common in such experimental devices--have a drastic impact on the operation of embedded software.

Finally, uploading the compiled program to the target is not fully reliable; it is not unusual for the transfer to introduce errors into the object code.

As mentioned previously, typical microcontroller applications do not use an operating system. There is no console, no log file, nor any other standard error-reporting mechanism. In consequence, embedded software often fails silently, with no feedback regarding the cause of the fault. In this situation, a simple Hello World program is the key to creating a minimally functional development environment. Example 1 is such a program.

/* This program flashes the LED connected to pin 1 of port 2 on
the MSP430F149.  The easyWeb2 development board has an LED
connected in this way. */

#include <io.h>

int main(void) {

  P2DIR=0xFF;  /* Configure all pins on port 2 as outputs. */
  P2OUT=0x02;  /* Set pin 1 to the high state; all others to
               the low state. The mask "0x01" would set pin 0
               to the high state, "0x04" would set pin 2
               to the high state, etc. */

  for(;;) {
    /* The following two lines implement a very crude delay loop.
       The actual length of the delay can vary significantly.
       This approach may not work with all compilers. */
    volatile int i;        /* Declare "i" as volatile ... */
    for(i=0;i<20000;i++);  /* ... so that this loop will not be optimized. */

    P2OUT=~P2OUT;          /* Toggle the state of all pins on port 2.  Every
                           pin that is high will be set low, and every
                           pin that is low will be set high.  */


Example 1. An embedded Hello World

Note the volatile keyword--a very common occurrence in embedded C development. This keyword most often designates a variable that may be read or written to in the background (usually by an interrupt service routine, or ISR).

The compiler disables many optimizations for a volatile variable (such as caching it in a register). In the example, the delay loop would run much faster if i were not volatile; the compiler could even remove the loop altogether. Some compilers may still render the delay loop ineffective despite the use of volatile, but mspgcc does not do so.

Save the code from Example 1 in a file (such as hello-world.c) and compile it with:

$ msp430-gcc -std=gnu89 -pedantic -W -Wall -Os -mmcu=msp430x149 \
	-o hello-world.elf hello-world.c

This produces the binary file hello-world.elf. Now, load the file onto the target using the pyJTAG tool.

$ msp430-jtag -epv hello-world.elf

You should see a flashing LED on your development board. You may have to type (note the .py extension) instead of just msp430-jtag, depending on how you installed pyJTAG.

If you are not using an easyWeb2 development board, your LED may be connected to a different port and pin of the microcontroller; in that case, you will need to make a minor change to the code. For example, for the TI MSP430 Development Tool model MSP-FET430X140, use port 1 (P1DIR and P1OUT) pin 0 (P1OUT=0x01 instead of P2OUT=0x02).

Choosing the right compiler options is especially important for embedded systems. In particular, note the -mmcu=msp430x149 option, which selects the correct MSP430 family member for the easyWeb2 development board. You will need to change this (see the "Compiler options" section of the mspgcc manual) if you are using a different variant of the MSP430. The -std=gnu89 option selects the ISO C 1989 standard, with GCC extensions. Some mspgcc header files require the extensions in order to compile. gnu89 is currently the default if you do not specify any -std option.

The -Os option tells the compiler to optimize the code for space rather than speed. While space optimization is not necessary in this small example, it is a common requirement when compiling more complex embedded software. In order to improve standards compliance and catch some unsafe constructs in the code, use the -pedantic, -W (capital W), and -Wall options. The GCC manual describes these options in detail. Finally, the -o option specifies the output filename.

It is also important to understand the options to the target programming tool (pyJTAG in this case). The example given uses three single-letter options (-epv). The first option erases all the flash memory of the target device, the second programs the device, and the third verifies the programming operation. The file used to program and verify the device is the last item on the command line in the example. For more information on pyJTAG, use the -h option (msp430-jtag -h or -h), or see the pyJTAG documentation in the mspgcc manual.

The highly primitive nature of the embedded Hello World is deliberate and very important. You want the lowest possible chance of something going wrong. This kind of program is something that you will write many times if you work with embedded systems. If the program runs, you immediately have the answers to several key questions about your development environment:

The next article will cover several important embedded development techniques. These design patterns form the foundation for the subsequent discussion of connected embedded systems.

Appendix A

Installing the development tools

This appendix describes how to install the mspgcc suite of tools for the MSP430 microcontroller. See to download the tools and additional documentation.

Note that some MSP430 development boards (such as the Texas Instruments MSP430 Development Tool, model MSP-FET430X140) power themselves solely through the PC parallel port, via the JTAG adapter.

If you are using such a board and your uploaded program does not run, you may need to give the --no-close option to the pyJTAG tool. Here is an example.

$ msp430-jtag --no-close -epvr hello-world.elf

You may have to type instead of msp430-jtag, depending on how you installed pyJTAG. The --no-close option is a very recent feature at the time of this writing, so you may need to download and build pyJTAG from source if your development hardware requires it.

In any case, you will need a free parallel port in order to use pyJTAG.

Windows installation

Installing mspgcc under Windows is very simple. Download the latest mspgcc-win32 package (mspgcc-20060119.exe), run the executable file, and follow the prompts. According to the mspgcc manual (see the "Windows installation" section), the installer works with Windows 98, ME, NT, 2000, and XP.

Linux installation

Make sure that the parallel port you are planning to use with pyJTAG is not already in use by a daemon process (such as lpd). The pyJTAG utility also requires the ppdev kernel module, unless you compiled it otherwise.

If you want to run pyJTAG as an ordinary user, you can make the port (/dev/parport0 by default) world-readable and writable. Alternatively, add your username to the port's group in /etc/group, then log out and back in again for the change to take effect. The group should also be able to read to and write from the port for this to work.

Sourceforge has source code tar archives and RPM packages of mspgcc. In order to run a recent version, however, it is best to build mspgcc by checking out some of the components from CVS.

The "Building mspgcc from source code" section of the mspgcc manual and the mikrocontroller site both provide detailed building instructions for mspgcc. The discussion here follows the latter set of directions. Note that it is not necessary to build gdb (the GNU debugger) or the gdbproxy (which enables gdb to debug MSP430 programs running on an actual target) for these articles.

In order to build mspgcc from source, first make a temporary subdirectory in which you will compile the tools. Your home directory is a good place for this temporary subdirectory. You will also need a working Internet connection. (Broadband is recommended.) You should know the root password to your system and must use a 2.4 or higher series Linux kernel. (A 2.4 series kernel was used to verify the instructions given here).

$ mkdir t
$ cd t

Next, create the binutils and add them to your path.

$ wget
$ tar xjvf binutils-2.14.tar.bz2
$ cd binutils-2.14
$ ./configure --prefix=/usr/local/msp430 --target=msp430
$ make

$ su   #You will be prompted for the root password.
# make install
# exit

$ cd ..
$ export PATH=/usr/local/msp430/bin:$PATH

Now, build the mspgcc compiler. When prompted for the CVS password, just press Enter. Note that the mspgcc numbering does not correspond to the GCC core numbering; mspgcc version 3.3 actually matches GCC core version 3.2.3.

$ wget     
$ tar xjvf gcc-core-3.2.3.tar.bz2

$ cvs login
$ cvs -z3 co gcc/gcc-3.3
$ cp -r gcc/gcc-3.3/* gcc-3.2.3/

$ cd gcc-3.2.3
$ ./configure --prefix=/usr/local/msp430 --target=msp430
$ make

Now, become the superuser and install the mspgcc compiler. Under some Linux installations, you may have to set the path again (export PATH=/usr/local/msp430/bin:$PATH) every time after becoming the superuser, but this is usually not the case.

$ su
# make install
# exit

$ cd ..

Create the MSP430 libc. If you need to log in to CVS again, you can always do so by reissuing the command cvs login

$ cvs -z3 co msp430-libc

$ cd msp430-libc/src
$ make

$ su
# make install
# exit

$ cd ../..

Finally, build the pyJTAG tool, which you can use to upload your compiled firmware to the target. The tool requires the Python programming language, version 2.2 or later. Most major Linux distributions include Python. Use the command python -V to check your version.

If you want to use something other than your distribution's default Python to run pyJTAG, you can substitute commands such as python2.3 for python. Of course, you need to have the additional Python version installed beforehand. Several different versions of Python can coexist on the system without problems.

$ cvs -z3 co jtag  
$ cvs -z3 co python

$ cd jtag
$ make
$ su

Now you must ensure that your /etc/ contains a line /usr/local/lib. If necessary, edit the file (as root) to add the required line. Note that some Linux distributions (such as Gentoo) generate from some other file automatically, in which case you will have to change that file instead.

Also make sure that the ldconfig command is in your path before attempting to install the JTAG libraries. Usually, ldconfig is in the /sbin directory.

# export PATH=/sbin:$PATH  # So that "ldconfig" can be found.

# make install 

# cd python
# python install #You can use "python2.3", etc. instead.
# cd ../..

# cd python  #Note that this is a different "python" directory.
# python install #Use the exact same "python" command as before.

# chmod 755

If you are using anything other than python (for example, python2.3), edit to change python in the top line (to python2.3, for instance).

# cp /usr/local/msp430/bin/msp430-jtag

# cd ../..
# rm -Rf t

# exit
$ cd

Add the directory /usr/local/msp430/bin permanently to your path (typically in your .bash_profile).

Appendix B

Installing and handling the hardware

You will need the following components in order to follow the examples in this series of articles:

If you want to substitute another development board for the easyWeb2, see Choosing a Platform for the list of required features. The discussion in this appendix assumes the use of easyWeb2.

The work required to set up the hardware is absolutely minimal, but please read this appendix through to the end if you have little experience working with open circuit boards. The information presented here will help you avoid frustration, and possible damage to the equipment.

An AC adapter (the familiar "power brick") is a simple, reliable, and inexpensive solution for supplying DC power. Many distributors (such as Spark Fun Electronics) will offer you an appropriate adapter when you buy the easyWeb2 development board. This is the safest option if you have any doubts about your source of power.

The serial cable (needed for later articles in this series) needs only the transmit, receive, and ground lines--the additional lines of a full null modem will go unused. This can save you a lot of effort if you build your own cables.

Many embedded devices contain static-sensitive components, which a single careless touch can destroy. The next section describes several basic techniques for avoiding static discharge damage.

It is safest if you turn off all components (including any peripherals attached to the PC) before starting.

Connect the JTAG adapter to the PC's parallel port. (You will almost certainly need an extension cable.) Plug the other end of the cable into the easyWeb2--there is a connector labeled JTAG on the board. Make sure that red stripe on the cable is toward the pin 1 side of this connector. The location of pin 1 is clearly indicated on the board, right beside the JTAG connector. Figure 2 shows the JTAG adapter correctly attached to the easyWeb2.

Finally, attach the AC adapter to the board.

A note on static electricity

Static electricity poses a grave danger to many electronic components. It takes only a gentle touch to pass a charge from your body to the device, potentially causing permanent damage to the system.

Related Reading

Linux Device Drivers
By Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman

Ideally, you should wear a grounded wrist strap when handling open circuit boards and especially individual components. You should also have a grounded antistatic mat on your work surface. Note that these tools are designed with safety features--grounding yourself with just a plain piece of wire can easily give you a deadly electric shock!

Keep any loose circuit boards in antistatic bags. These bags are often silver in color, but this is not universal. If you have ever upgraded your PC and kept the packaging, you should have some antistatic bags around.

Always fold the open end of the bag and tuck the excess underneath the board so that the weight keeps it folded. Use antistatic foam to line containers that hold unmounted sensitive parts, such as microcontrollers. Put the components on the foam. The black squares on which the 486 and MSP430 chips rest in Figure 1 are made of this material. Note that the chips were placed pin side up in Figure 1 just to take the picture; the correct position for storage is with the pins on the foam.

Antistatic bags are often an acceptable substitute to the antistatic mat and wrist strap. Spread the bag on your work surface, touch the bag to dissipate static, and then place the board fully on the bag. When putting the board down, make sure that your hand makes contact with the bag before any part of the board does. You should also touch the bag on which the device is resting before picking up or otherwise handling the board. Figure 2 shows the easyWeb2 placed on top of an antistatic bag.

One way of dissipating a high static charge is to touch a fully closed metal case of a PC. The machine has to be plugged in, but turning it on is unnecessary. This method of dealing with static, however, requires constant vigilance, because you must remember to discharge yourself frequently. In addition, you still have to follow the directions in the previous paragraph for handling your hardware.

Common sense antistatic precautions are important as well. Use a work surface (such as a wooden board) that does not generate a static charge readily. Wear 100 percent cotton clothing instead of synthetics when working with open circuit boards or unmounted components. Maintain sufficient air humidity, and be aware that walking on carpet can quickly build up a very high static charge.

George Belotsky is a software architect who has done extensive work on high-performance internet servers, as well as hard real-time and embedded systems.

Return to

Copyright © 2009 O'Reilly Media, Inc.