Migrating from x86 to PowerPC, Part 7: Basic design of the vehicle control module

Hooking up external components

Get an overview of some design decisions involved in configuring a secondary processor to handle maintenance tasks on your robot submarine, and see some of the setup code allowing the subordinate processor to interact with the main system.


Lewin Edwards (sysadm@zws.com), Design Engineer, Freelance

Lewin A.R.W. Edwards works for a Fortune 50 company as a wireless security/fire safety device design engineer. Prior to that, he spent five years developing x86, ARM and PA-RISC-based networked multimedia appliances at Digi-Frame Inc. He has extensive experience in encryption and security software and is the author of two books on embedded systems development.

06 September 2005

The last six episodes of this series have focused closely on the Kuro Box hardware and techniques for programming various functionality within the PowerPC® Linux™ environment. The next few articles focus on designing the hardware that talks to the "real stuff" on your submarine (motors, sensors, and so forth). I'll return to the Kuro Box frequently, but the primary focus now is on the hardware and the deeply embedded real-time code that runs on the external microcontroller(s).

Let me forestall an obvious question here: I do not intend to publish PCB artwork for the hardware parts of this project just yet. The reason for this is that I'm still iterating and spinning the design -- the hardware you're reading about here is a third-generation design that differs quite a bit from the previous generations, and I hope it represents the final fieldable version of this project. I really don't want to see people wasting money on prerelease board designs.

As always, I encourage you to submit suggestions and questions in the forum for this series. Since this is a live, work-in-progress project, your input could make big changes!

The goals for this article are:

  1. To introduce the block-level E-2 system architecture.
  2. To design a control board based around an 8-bit microcontroller, which will ultimately be capable of driving actuators (solenoids, steppers, and brushless DC motors) and acquiring data from various sensors.
  3. As a first step in the firmware, to establish bidirectional communications between the PowerPC host running Linux and the control board developed for Step 2.

System architecture

Over the remainder of this series, I'm going to use a lot of acronyms specific to the E-2 project. I'm documenting these on my personal Web site (see Resources), but the first two acronyms I'd like you to remember are VCM (Vehicle Control Module) and SCM (Science Control Module). In the context of this article series, the SCM is the Kuro Box, and the VCM is the small real-time board you'll start to build in this article. Below you'll see a block diagram of the system this series is teaching you to build. The VCM is essentially everything that's (a) not inside the Kuro Box, and (b) not shown in pink.

Figure 1. Block diagram of the robot submarine
Block diagram of the robot submarine

The color coding in this image is as follows: tan = storage, blue = software component, pink = power system component, yellow = actuator/output component, green = sensor/input component. All other coloring is cosmetic.

For the purposes of this article series, I'm using a 7Ah battery pack (specifically, two Powersonic PS-1270 12V/7Ah batteries) and a solar panel with nominally 36W of output. This is a convenient test setup that I have on my workbench at home; it's essentially a scale model of the Power Architecture™ systems on the actual E-2.

Sorcerer or Apprentice?

For those who are really interested, here are some more details on how this technology is applied in my submarine project. Although the hardware you see here is very similar to the control system in the sub, there's an important architectural difference. In the sub, the heavy processing iron (currently an Advantech PCM-5820 single-board x86 computer based on the AMD Geode processor) doesn't do the navigation tasks; it is powered down almost all of the time in order to conserve energy.

In fact, for the daylight hours, the submarine is configured in a minimum-power mode with practically everything switched off, so that the batteries can reach the maximum possible charge level. The actual mission is carried out at night -- the rationale for this being that underwater you'll need lights to see anything interesting regardless of what time it is, so you may as well spend the daytime just collecting energy.

As a result, the block diagram of the E-2 is slightly different from what you see in this article; it has all the same blocks, but the GPS receiver goes directly into the ATmega32. Through a little software and hardware cunning, a single UART on the ATmega32 services both the GPS and the SCM. From a conceptual standpoint, the other main differences are that all the software feedback loops (depth control, for instance) are closed within the ATmega32, and the engineering data log (EDL) is connected directly to that micro as well. The EDL is implemented on a standard SD or MMC card in SPI mode.

This architectural decision, by the way, is why I don't need to worry very much about security on the Linux side of the equation: during normal operation, the outside world simply cannot communicate with the Linux box. The only field communications interface during mission time is with the VCM, which is as secure as it needs to be.

Note that there are also a couple of additional function blocks in the E-2, designed to communicate with the device and help with recovering it if lost, which this article series doesn't get into. These modules will eventually be described in detail in the E-2 public information area on larwe.com; one of them is an emergency recovery beacon similar to an aircraft flight data recorder's "pinger," and the other is an off-the-shelf satellite transceiver.

Note: If you were planning to use these articles to build an actual vehicle, then at this point please read the Sorcerer or Apprentice sidebar, because it talks about important differences between this hardware design and the actual design used in E-2.

Design requirements

Now to get acquainted with a few of the design requirements for the board: Many of the actuators (solenoid valves, motors, and so on) needed are most readily available in 24V flavors, so the board should be designed to operate off a 24V battery supply. This raises the first interesting question of how to regulate the bus voltage down to a micro-friendly 5V.

Being a lazy sort, I'd usually take the easy way out and dump a simple linear regulator into an application like this, but dropping 24V down to 5V is just too big a step, as it would mean throwing away about 5W in that regulator for a relatively modest 250mA load. Use of a switcher is therefore mandatory, and if you refer to the schematic you'll see that I've used the dirt-cheap MC34063A in a direct crib of its step-down application note. There is nothing at all special about this circuit, and if you're trying to throw together a quick hack to experiment with the code I'm talking about here, feel free to use a 7805, or just power your board off a lab power supply. Substantial heatsinking and a TO-3 package on the regulator will be necessary if you use a 7805 with a 24V input voltage.

Fulfilling Step 3 in the goals mentioned above requires choosing a sensible hardware interface, and overlying software protocol, between the VCM and SCM. There are many ways to achieve this, but the method I've chosen is an asynchronous serial interface with RS232-compatible levels. Please note that this probably wouldn't be the ideal choice for a real integrated application that you were building from scratch. If you were using a bare MPC8241 part, for instance, the right thing to do would be simply to put some 3.3V-5V level shifting in place and connect directly to one of the MPC8241's serial ports. Unfortunately, we're fighting the Kuro design a bit; one serial port is reserved for debug output, and the other is connected to the supervisor/watchdog chip.

Getting a serial port

The great thing about async serial connections, however, is that they can be plugged into almost any hardware platform on the planet. In the case of the Kuro Box, you can either go in through the debugging serial port, or you can put a standard level-shifter on the micro and attach it to the Kuro Box through a USB-to-serial converter.

This discussion follows the latter route, partly because the debug port is constantly in use by the kernel, but mostly because this way you can use the same VCM hardware to talk to a Microsoft® Windows® machine running Cygwin, or a regular PC running Linux, or indeed almost anything else with a standard serial port.

I'm using a Keyspan USA-19W USB-to-serial adapter in this project, because I happen to have it lying around; there are numerous other such adapters supported by Linux. If you followed my instructions in the third article of this series, you have a complete set of modules installed on your Kuro Box already; this includes support for Keyspan and Belkin adapters, among others, as well as FTDI USB-serial solutions. The only thing you need to do is to create the necessary /dev/ttyUSB* nodes; if you unpack the sourcecode tarball for this article series, you'll find a nested tarball called ttyusb.tar.gz. Move this into the root directory of your Kuro and extract it; this will create all the necessary ttyUSB* nodes for you.

Your friend, the microcontroller

Now, I've chosen to use an Atmel Atmega32 microcontroller as the core of the VCM. This happens to be an ideal choice for me, because I'm very comfortable with programming this micro, it's 5V-compatible (and hence easily interfaced to all the power electronics; it can be a bit irksome using 3.3V micros in projects like this), and it operates over a wide temperature range. It's also supported very well by free or low-cost hardware and software tools, and most of those tools work within Linux. Most of the same things, except for the voltage comment, are also true for the MSP430 series -- if you're more familiar with that microcontroller, then you can probably port 75% of the circuit and code across without much difficulty.

Here's a schematic of the circuit we're working with in this article. It's little more than the microcontroller and serial interface. Also click to see a larger version of this schematic.

Figure 2. The Vehicle Control Module
VCM Schematic

To flash this chip, you will need an in-system programmer such as the Atmel AVR-ISP cable, the STK500 development board, or a third-party tool. The software tools you'll need are gcc, binutils and the AVR runtime library, avrlibc. All of these tools (at least the versions specified in the Download table below) build and run perfectly under Linux, MacOS or Cygwin. In fact, if you so desire, you can even build and run the AVR development tools on the Kuro Box itself.

Building the AVR tools

Windows users can avoid having to compile the various components by downloading the complete WinAVR package, also mentioned in Resources. However, the build process is very simple:

First, build binutils. Unpack the tarball, cd into the source directory, then execute the following commands:

Listing 1. Building binutils
./configure --target=avr --program-prefix="avr-"
make install

Now build gcc. Again, unpack the tarball, cd into the source directory, then execute the following commands:

Listing 2. Building gcc
./configure --target=avr --program-prefix="avr-" --enable-languages=c
make install

Finally, build the avrlibc library. Unpack the tarball, cd into the source directory, then execute the following commands:

Listing 3. Building avrlibc
./domake install

You might also want to install a command-line programming utility (my makefile uses uisp, available from the links in Resources). However, take warning! From time to time, Atmel changes the communication protocol used by its serial programming tools. When you download and run a new version of AVR Studio for Windows, it will often prompt you to update your STK500's firmware without warning you of the consequences. One of these "flag days" occurred very recently, and it has completely broken third-party support for the STK500. The only open-source program I'm aware of that's currently capable of using this new STK500 protocol is the latest beta of avrdude; older programs such as uisp are effectively useless. If you have a working system based on third-party tools, I advise that you never run AVR Studio when your STK500 (or AVRISP cable) is connected.

Please also be aware that these articles won't provide you with a complete from-the-ground-up introduction to programming the AVR; what I'm trying to describe here is the set of specific technical challenges in my application and how I solved them. However, I do hope that as I introduce the hardware and firmware in bite-size chunks month by month, you'll be able to study the changes alongside the library and chip documentation, and hence get a better understanding of what's going on.

Building the AVR firmware

To build the firmware for the AVR side, assuming you already have avrgcc properly installed, simply extract the source tarball for this article and run make in the vcm_399 directory. Take a moment to examine the structure of the program. In particular, note how the interrupt syntax works. The avrlibc library by default vectors all the AVR interrupts to a do-nothing handler. To revector an interrupt, rather than writing a normal function name, you use the SIGNAL macro with an argument naming the interrupt to be vectored -- followed immediately by the code block to be inserted. For instance, in serial.c you'll see the serial receive interrupt declared as:

Listing 4. A signal handler
         // code goes here

WARNING: The signal name definitions are not 100% identical between different AVR variants, and sometimes their meanings can be a little confusing. Therefore, C code that uses interrupts is not guaranteed to be portable, even if both AVRs in question share the interrupt-generating hardware feature you're interested in. If your interrupts are inexplicably not firing, look at the appropriate header file in /usr/local/avr/include/avr (assuming you used the default install location for everything) and verify that you used the correct interrupt name for the particular chip you're using.

Because of this potential for confusion, when you're bringing up a new design, I strongly advise using a spare I/O as an interrupt flag. Before you start puzzling out obscure interrupt priority questions, just do a quick sanity check -- force your interrupts to fire, and verify on the scope that you're reaching the correct code point.

Another interesting feature you might want to look at is the EEPROM handling code in eeconf.c. Although nothing is stored in there yet, in the final product the EEPROM is used for some important calibration constants (accelerometer zero roll/pitch values, for instance). The code in eeconf.c implements a simple checksummed redundant configuration scheme. The avrlibc library provides a convenient framework for polled EEPROM read/write code. If you have higher performance requirements and want to use interrupt-driven writes, you have to roll your own.

A handy hint: To get a quick look at ROM and RAM utilization in your avrgcc program, use avr-objdump to look at the section headers -- in this case, avr-objdump -h 399.elf will show you what you need to know (look at the Size column, and ignore .stab and .stabstr, which are symbol tables that don't get uploaded to the chip).

Efficiency, or the lack thereof

Speaking of memory, you should be aware that avrlibc isn't very efficient size-wise. For instance, if you use printf, you'll pull in a huge amount of code (this is a common problem in embedded systems). There are various stripped-down printf functions you can use, or you can simply implement by hand the bare functionality you need. Since my application doesn't need to transmogrify much output into human-readable formats, I chose the latter route; look at utils.c for examples of that code. (These functions are not used in the code for this article; I just include them by way of completeness).

If you refer to main.c and serial.c, you'll see that the device uses a very simple packet format to communicate with its host; packets begin with ! and end with #. The VCM transmits a version ID packet at startup, and thereafter once every three seconds it sends a "ping" packet to show the contents of a RAM variable. The SCM can send a packet to change the contents of that RAM variable; once it does so, the VCM announces !VALCHANGE# and subsequent ping packets show the updated variable.

Obviously we will add further layers of complexity to protect the integrity of data in transit; this is just a first step at bringing up bidirectional comms between the two devices.

In the AVR code, there is also a timer running at approximately 30Hz; this times the periodic output packets sent by the VCM. Note the general-purpose software timer architecture; the E-2 module needs a large number of timers for various periodic tasks.

Talking to the microcontroller

Now take a look in the scmd directory (it stands for SCM Daemon, by the way) in the source tarball. This is the Kuro Box side of the application. This simple applet sets /dev/ttyUSB0 to 19200bps, 8N1, then loops infinitely. In the loop, it waits for a valid packet to be received and displays it onscreen. After every fourth incoming packet, the SCM sends an incremented value-update packet back to the VCM. I'm going to ask you to take the Kuro-side serial code on faith a bit -- working with serial ports in Linux is a little irritating because you're simultaneously dealing with the port driver and terminal interface code on top of it.

Here's sample output from scmd talking to the VCM code in the tarball for this article:

Listing 5. Talking to the VCM
root@KURO-BOX:~/article7/scmd# ./scmd
IBM developerWorks Kuro Box to AVR Demo Applet
Waiting for AVR to start sending...
Rx packet: "VCM V0.04"
Rx packet: "VAL=0"
Rx packet: "VAL=0"
Rx packet: "VAL=0"
Tx packet: "!A#"
Rx packet: "VALCHANGE"
Rx packet: "VAL=A"
Rx packet: "VAL=A"
Rx packet: "VAL=A"
Tx packet: "!B#"
Rx packet: "VALCHANGE"
Rx packet: "VAL=B"
Rx packet: "VAL=B"

With the two system modules talking to each other, world domination is only a short step away. In the next article, you'll see how to add I/O expansion and actuators to the VCM, and the Kuro Box will finally be able to move and wiggle things in the real world.


The downloads for this article are being updated. Please try to download later.



Get products and technologies

  • Download the sourcecode referenced in this article from the Download table above. The usual warning applies to Internet Explorer users -- make sure to save the file as something.tar.gz.
  • In addition the the two AVR tools in the download table above, also download avrlibc from http://www.nongnu.org/avr-libc/.
  • If you're using Windows for your AVR development, download the precompiled WinAVR from SourceForge.
  • If you'd prefer a simple USB interface over old-style serial communications, look at FTDI's range of products -- as well as selling bare interface chips, they also have ready-assemble modules that fit into a standard DIP socket.
  • Another vendor of USB-to-serial modules for embedded projects is Pololu. By the way, you can also use these sorts of products to connect the Kuro Box's debugging serial port to your PC.
  • The entry-level development platform for Atmel's AVR microcontrollers is the STK500. The board is readily available from retailers such as Digi-Key.
  • Olimex sells inexpensive programmers and evaluation boards for numerous micros including the AVR series (and the MSP430, among others). Note that the circuit design I'm implementing here uses the JTAG pins for other functions, so do not buy the AVR-JTAG or AVR-USB-JTAG devices to work with this circuit!
  • Download datasheets for the AVR range of microcontrollers from Atmel's Web site.
  • The batteries I'm using in this project are PowerSonic PS-1270 12V, 7Ah sealed lead-acid (or equivalents). You can download some basic specs for them. Note that the 1270 form factor is standardized; Numerous other parties offer almost identical batteries of exactly the same dimensions.
  • The solar cells we'll be using are nominally 0.54V Voc, 6000mA Isc. An equivalent model is type 04-1192 from Silicon Solar Inc's catalog.



developerWorks: Sign in

Required fields are indicated with an asterisk (*).

Need an IBM ID?
Forgot your IBM ID?

Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.


All information submitted is secure.

Dig deeper into developerWorks

Zone=Multicore acceleration
ArticleTitle=Migrating from x86 to PowerPC, Part 7: Basic design of the vehicle control module