How to build GNU/Linux for an embedded x86 computer

Recently, I had a customer who needed an embedded Linux distribution running on an Advantech PCM-9371 single board computer (SBC).  The PCM-9371 contains a low voltage Celeron or Pentium III processor.  This article describes why the Openembedded build system was chosen and a few tips for running Openembedded on a x86 system.

The hard way!

There are many ways to put Linux on a x86 embedded system.  There are hundreds of distributions out there and the temptation is always to do something “quick” and just try to trim down one of the standard distributions.  Other shortcuts are often taken, such as compiling your application on a workstation that is running a different distribution and different versions of the libraries used in the embedded systems.  This approach can work, but there are many possible pitfalls:

  • Several years down the road, it will be difficult to compile applications for your target system as the libraries on the target system are very dated compared to tools and libraries used in standard desktop distributions.  What this means is you will need to keep a “golden” compile machine around for the life of your project — not fun!  I went through an experience like this on a previous version of this same project where it took us a week to set up a build machine to compile applications using a very old version of Debian.
  • It is difficult to gather GPL sources used to build the distribution you are using.  You are required to supply GPL source code upon request to customers who purchase your product.
  • To build applications correctly, you really need a build machine that is running the same distribution as the target, unless you set up a cross-compilation or scratchbox environment.
  • Most distributions are quite large and have difficulty fitting on CF card.
  • Most distributions are difficult to customize in a clean, systematic way.


Considering the disadvantages of using an standard x86 distribution for this project, I chose to use OpenEmbedded (OE).  The OpenEmbedded project ( ) is a full featured build system for building embedded Linux distributions.  The development is done on a Linux workstation of your choice and the entire distribution is cross-compiled to the architecture of your choice.  The entire build process is automated, including building the toolchain and an image that can be installed on the target embedded system.  Some of the features of OpenEmbedded are:

  • Over 3000 packages that can be built.  About anything you would ever need for an embedded system.
  • Support for a wide variety of target architectures.  ARM and x86 processors are well supported.
  • Build system is very self contained.  This means you can do the builds on a variety of different host machines.  Many of the tools OE needs are built by OE, so there is very little dependence on host tools besides a few basics such as Python, make, and other standard tools.  This also means it is much easier to pull the build system out of the archives in several years, load it on a current machine, and do a build.
  • All source code used in the build is downloaded, so GPL compliance is easy.
  • and the list goes on …

Build and Installation

Setting up an OE build is beyond the scope of this article, but it basically involves selecting a machine and distribution.  In this case, I chose the x86 machine and the generic OE distribution.  Several hours later, I had an image in the form of a tar.gz file that I decompressed to a Compact Flash (CF) card.  After installing grub on the CF card, I had a booting Linux distribution that included all the basics (like ssh, ipkg package manager, shell, standard file utilities, etc) in less than 4MB of disk space.

Adding GTK+ and Xwindows

This system required support for GTK+ and Xwindows.  To add this involved running the following commands: bitbake xserver-kdrive and bitbake gtk+.  The OE build system then automatically downloaded and compiled the need packages.  The image size is now around 20MB — still fits very easily on a CF card.

Getting X running

There are several options for running X on a x86 system.  In this case, I chose the quickest way so that my customer could get started with application integration as quickly as possible.  Linux and Xwindows support the standard VESA Framebuffer mode.  Then can be enabled by selecting the CONFIG_FB_VESA kernel config option.  The kdrive version of X can then be started by running Xvesa.  In the future, we may move to an accelerated X driver if needed.


We now have Linux running off of a CF card with full X/GTK+ support and the customer can proceed with integration, testing and application development.  Getting to this point took about 1 day of development as we did not encounter any major problems — much less time than it took to resurrect an old build environment used in previous versions of the project.  Future work will involve integrating applications into the OE build system, and customizing the distribution as needed.  Openembedded has proved to be a very valuable tool for getting embedded Linux systems running quickly and maintaining them in a controlled way.


Adding software to a Moxa UC7408 using OpenEmbedded

One of the big advantages of using Linux in embedded systems is the thousands of applications and drivers available for it ( ).  One of the challenges of Embedded Linux is building these applications.  Building applications for an embedded system often involves cross-compiling which is frustrating on a good day.  This article details how to use OpenEmbedded (OE) with the existing toolchain Moxa provides to build a number of applications for the Moxa UC7408.

Web Application Support

My needs for this project were to build a web application that ran on the UC7408 (See for a review of the Moxa UC7408).  The Moxa firmware is fairly full featured and provides php for web application development.  This is probably fine for many applications, but I prefer to build web applications as detailed in this article: .  Because the rest of the application is written in Python, there are advantages to also implementing the web application in Python.  I also wanted to use the sqlite database.  A quick look at the php supplied with the Moxa firmware suggested it was built without sqlite support.  In summary, I needed the following components:

  • Python
  • Clearsilver
  • sqlite
  • minicom
  • vim
  • strace
  • subversion
  • wget

The above is a fairly small list, but what you don’t see are all the dependencies that also need to be built and installed.  This ends up being many more components.   Some of the items are for development only, but this is Linux — why not have nice tools running on the target system?

OE to the rescue

Ideally, the Moxa system would have a complete root file system built with OE running on it.  But I did not have the time or budget to implement this, so I did the next best thing — use the rootfs and toolchain supplied by Moxa along with OE to compile just the applications I needed.  Typically, OE builds the toolchain and Glibc, but fortunately OE provides a very slick way to use an external toolchain and glibc with OE.  How to do this is detailed in the OE manual:  Below is the setup I used:

Environment variables:

export PRE_BUILT=/usr/local/mxscaleb/armv5b-linux

export CCACHE_DIR="${TOPDIR}/ccache"
export PYTHONPATH="${TOPDIR}/bitbake/lib"
export BBPATH="${TOPDIR}:${TOPDIR}/openembedded:${TOPDIR}/bitbake"
export PATH="${TOPDIR}/bitbake/bin:${TOOLCHAIN}:${PATH}"
export LANG=C

Local.conf file:

DL_DIR = "/build/sva_oe/downloads"
BBFILES := "/build/sva_oe/openembedded/packages/*/*.bb"
PREFERRED_PROVIDERS = "virtual/qte:qte virtual/libqpe:libqpe-opie"
PREFERRED_PROVIDERS += " virtual/libsdl:libsdl-qpe"
PREFERRED_PROVIDERS += " virtual/${TARGET_PREFIX}gcc-initial:gcc-cross-initial"
PREFERRED_PROVIDERS += " virtual/${TARGET_PREFIX}gcc:gcc-cross"
PREFERRED_PROVIDERS += " virtual/${TARGET_PREFIX}g++:gcc-cross"
PREFERRED_PROVIDER_virtual/libx11 = "diet-x11"
ASSUME_PROVIDED += " virtual/libc "
MACHINE = "moxa"
IPKG_ARCHS = "all arm armv4 armv5te xscale ${MACHINE}"
TARGET_CC_ARCH = "-mcpu=xscale"
TARGET_OS = "linux"
TARGET_FPU = "soft"
DISTRO = "moxa-disro"
DISTRO_NAME = "moxa-distro"
DISTRO_TYPE = "release"
INHERIT += " package_ipk package_tar debian"
IMAGE_FSTYPES = "jffs2 tar"
export CC  = "mxscaleb-gcc-3.3.2 ${HOST_CC_ARCH}"
export CXX = "mxscaleb-g++ ${HOST_CC_ARCH}"
export CPP = "mxscaleb-gcc-3.3.2 -E"
export LD = "mxscaleb-ld"
export AR  = "mxscaleb-ar"
export AS  = "mxscaleb-as"
export RANLIB  = "mxscaleb-ranlib"
export STRIP  = "mxscaleb-strip"
TARGET_CPPFLAGS_append = " -I${PRE_BUILT}/include "
TARGET_LDFLAGS_prepend = " -L${PRE_BUILT}/lib -Wl,-rpath-link, ...
${PRE_BUILT}/lib -Wl,-rpath-link,${PRE_BUILT}/qt2/lib "

With the above setup, I was able to build the applications I needed with very little effort.  There were a few little problems I ran into, but I was able to quickly work around them.  The result is a number of packages that can be installed on the target system:

bigreqsproto-dev-X11R7.0-1.0.2-r0.tar.gz      python-crypt-2.4.3-ml0.tar.gz
busybox-1.2.1-r1.3.tar.gz                     python-curses-2.4.3-ml1.tar.gz
busybox-udhcpd-1.2.1-r1.3.tar.gz              python-datetime-2.4.3-ml0.tar.gz
clearsilver-0.10.3-r0.tar.gz                  python-db-2.4.3-ml0.tar.gz
clearsilver-dbg-0.10.3-r0.tar.gz              python-devel-2.4.3-ml0.tar.gz
clearsilver-dev-0.10.3-r0.tar.gz              python-distutils-2.4.3-ml0.tar.gz
clearsilver-doc-0.10.3-r0.tar.gz              python-email-2.4.3-ml0.tar.gz
inputproto-dev-X11R7.0-1.3.2-r0.tar.gz        python-fcntl-2.4.3-ml0.tar.gz
ipkg-0.99.163-r1.tar.gz                       python-gdbm-2.4.3-ml0.tar.gz
ipkg-dbg-0.99.163-r1.tar.gz                   python-hotshot-2.4.3-ml0.tar.gz
ipkg-dev-0.99.163-r1.tar.gz                   python-html-2.4.3-ml0.tar.gz
kbproto-dev-X11R7.1-1.0.3-r0.tar.gz           python-idle-2.4.3-ml0.tar.gz
libapr-0-0-0.9.12-r0.tar.gz                   python-image-2.4.3-ml0.tar.gz
libapr-0-bin-0.9.12-r0.tar.gz                 python-io-2.4.3-ml0.tar.gz
libapr-0-dev-0.9.12-r0.tar.gz                 python-lang-2.4.3-ml0.tar.gz
libaprutil-0-0-0.9.12-r0.tar.gz               python-lib-old-and-deprecated-2.4.3-ml0.tar.gz
libaprutil-0-bin-0.9.12-r0.tar.gz             python-logging-2.4.3-ml0.tar.gz
libaprutil-0-dev-0.9.12-r0.tar.gz             python-mailbox-2.4.3-ml0.tar.gz
libcrypto0.9.7-0.9.7g-r1.tar.gz               python-math-2.4.3-ml0.tar.gz
libexpat-bin-2.0.0-r1.tar.gz                  python-mime-2.4.3-ml0.tar.gz
libexpat-dev-2.0.0-r1.tar.gz                  python-mmap-2.4.3-ml0.tar.gz
libexpat-doc-2.0.0-r1.tar.gz                  python-netclient-2.4.3-ml1.tar.gz
libexpat1-2.0.0-r1.tar.gz                     python-netserver-2.4.3-ml0.tar.gz
libgcrypt-dbg-1.2.2-r0.tar.gz                 python-pickle-2.4.3-ml0.tar.gz
libgcrypt-dev-1.2.2-r0.tar.gz                 python-pprint-2.4.3-ml0.tar.gz
libgcrypt-doc-1.2.2-r0.tar.gz                 python-profile-2.4.3-ml0.tar.gz
libgcrypt11-1.2.2-r0.tar.gz                   python-pydoc-2.4.3-ml0.tar.gz
libgdbm-dbg-1.8.3-r2.tar.gz                   python-pyserial-2.2-r1.tar.gz
libgdbm-dev-1.8.3-r2.tar.gz                   python-pysqlite2-2.2.2-ml1.tar.gz
libgdbm-doc-1.8.3-r2.tar.gz                   python-pyxml-0.8.4-ml0.tar.gz
libgdbm3-1.8.3-r2.tar.gz                      python-re-2.4.3-ml0.tar.gz
libgnutls-bin-1.4.0-r1.tar.gz                 python-readline-2.4.3-ml0.tar.gz
libgnutls-dbg-1.4.0-r1.tar.gz                 python-resource-2.4.3-ml0.tar.gz
libgnutls-dev-1.4.0-r1.tar.gz                 python-shell-2.4.3-ml0.tar.gz
libgnutls-doc-1.4.0-r1.tar.gz                 python-stringold-2.4.3-ml0.tar.gz
libgnutls-extra13-1.4.0-r1.tar.gz             python-subprocess-2.4.3-ml0.tar.gz
libgnutls-locale-en+boldquot-1.4.0-r1.tar.gz  python-syslog-2.4.3-ml0.tar.gz
libgnutls-locale-en+quot-1.4.0-r1.tar.gz      python-terminal-2.4.3-ml0.tar.gz
libgnutls-locale-pl-1.4.0-r1.tar.gz           python-tests-2.4.3-ml0.tar.gz
libgnutls-openssl13-1.4.0-r1.tar.gz           python-textutils-2.4.3-ml0.tar.gz
libgnutls13-1.4.0-r1.tar.gz                   python-threading-2.4.3-ml0.tar.gz
libgpg-error-dbg-1.3-r1.tar.gz                python-tkinter-2.4.3-ml0.tar.gz
libgpg-error-dev-1.3-r1.tar.gz                python-unittest-2.4.3-ml0.tar.gz
libgpg-error-locale-de-1.3-r1.tar.gz          python-unixadmin-2.4.3-ml0.tar.gz
libgpg-error-locale-fr-1.3-r1.tar.gz          python-xml-2.4.3-ml0.tar.gz
libgpg-error-locale-pl-1.3-r1.tar.gz          python-xmlrpc-2.4.3-ml0.tar.gz
libgpg-error-locale-ro-1.3-r1.tar.gz          python-zlib-2.4.3-ml1.tar.gz
libgpg-error-locale-vi-1.3-r1.tar.gz          sqlite3-3.3.7-r2.tar.gz
libgpg-error0-1.3-r1.tar.gz                   sqlite3-dbg-3.3.7-r2.tar.gz
libice-dbg-X11R7.1-1.0.1-r0.tar.gz            strace-4.5.14-r3.tar.gz
libice-dev-X11R7.1-1.0.1-r0.tar.gz            strace-dbg-4.5.14-r3.tar.gz
libice6-X11R7.1-1.0.1-r0.tar.gz               strace-doc-4.5.14-r3.tar.gz
libipkg-dev-0.99.163-r1.tar.gz                subversion-1.3.1-r1.tar.gz
libipkg0-0.99.163-r1.tar.gz                   subversion-dbg-1.3.1-r1.tar.gz
liblzo-dbg-1.08-r14.tar.gz                    subversion-dev-1.3.1-r1.tar.gz
liblzo-dev-1.08-r14.tar.gz                    subversion-doc-1.3.1-r1.tar.gz
liblzo1-1.08-r14.tar.gz                       subversion-locale-de-1.3.1-r1.tar.gz
libneon-bin-0.25.5-r0.tar.gz                  subversion-locale-es-1.3.1-r1.tar.gz
libneon-dev-0.25.5-r0.tar.gz                  subversion-locale-fr-1.3.1-r1.tar.gz
libneon-doc-0.25.5-r0.tar.gz                  subversion-locale-it-1.3.1-r1.tar.gz
libneon25-0.25.5-r0.tar.gz                    subversion-locale-ja-1.3.1-r1.tar.gz
libpython2.4-1.0-2.4.3-ml5.tar.gz             subversion-locale-ko-1.3.1-r1.tar.gz
libreadline-dbg-4.3-r3.tar.gz                 subversion-locale-nb-1.3.1-r1.tar.gz
libreadline-dev-4.3-r3.tar.gz                 subversion-locale-pl-1.3.1-r1.tar.gz
libreadline-doc-4.3-r3.tar.gz                 subversion-locale-pt-br-1.3.1-r1.tar.gz
libreadline4-4.3-r3.tar.gz                    subversion-locale-sv-1.3.1-r1.tar.gz
libsm-dbg-X11R7.1-1.0.1-r0.tar.gz             subversion-locale-zh-cn-1.3.1-r1.tar.gz
libsm-dev-X11R7.1-1.0.1-r0.tar.gz             subversion-locale-zh-tw-1.3.1-r1.tar.gz
libsm6-X11R7.1-1.0.1-r0.tar.gz                tcl-8.4.11-r3.tar.gz
libsqlite-bin-2.8.17-r2.tar.gz                tcl-dbg-8.4.11-r3.tar.gz
libsqlite-dbg-2.8.17-r2.tar.gz                tcl-dev-8.4.11-r3.tar.gz
libsqlite-dev-2.8.17-r2.tar.gz                tcl-doc-8.4.11-r3.tar.gz
libsqlite0-2.8.17-r2.tar.gz                   time-1.7-r0.tar.gz
libsqlite3-0-3.3.7-r2.tar.gz                  time-dbg-1.7-r0.tar.gz
libsqlite3-dev-3.3.7-r2.tar.gz                time-doc-1.7-r0.tar.gz
libssl0.9.7-0.9.7g-r1.tar.gz                  tmp
libx11-6-X11R7.1-1.0.1-r1.tar.gz              update-rc.d-0.7-r0.tar.gz
libx11-dbg-X11R7.1-1.0.1-r1.tar.gz            util-macros-dev-X11R7.1-1.0.2-r0.tar.gz
libx11-dev-X11R7.1-1.0.1-r1.tar.gz            vim-7.0-r0.tar.gz
libx11-doc-X11R7.1-1.0.1-r1.tar.gz            vim-doc-7.0-r0.tar.gz
libx11-locale-X11R7.1-1.0.1-r1.tar.gz         vim-help-7.0-r0.tar.gz
libxau-dbg-X11R7.1-1.0.1-r0.tar.gz            vim-syntax-7.0-r0.tar.gz
libxau-dev-X11R7.1-1.0.1-r0.tar.gz            vim-tutor-7.0-r0.tar.gz
libxau-doc-X11R7.1-1.0.1-r0.tar.gz            wget-1.9.1-r6.tar.gz
libxau6-X11R7.1-1.0.1-r0.tar.gz               wget-dbg-1.9.1-r6.tar.gz
libxdmcp-dbg-X11R7.1-1.0.1-r0.tar.gz          wget-doc-1.9.1-r6.tar.gz
libxdmcp-dev-X11R7.1-1.0.1-r0.tar.gz          wget-locale-bg-1.9.1-r6.tar.gz
libxdmcp6-X11R7.1-1.0.1-r0.tar.gz             wget-locale-ca-1.9.1-r6.tar.gz
libxml2-2.6.22-r3.tar.gz                      wget-locale-cs-1.9.1-r6.tar.gz
libxml2-dbg-2.6.22-r3.tar.gz                  wget-locale-da-1.9.1-r6.tar.gz
libxml2-dev-2.6.22-r3.tar.gz                  wget-locale-de-1.9.1-r6.tar.gz
libxml2-doc-2.6.22-r3.tar.gz                  wget-locale-el-1.9.1-r6.tar.gz
libxml2-utils-2.6.22-r3.tar.gz                wget-locale-es-1.9.1-r6.tar.gz
libxt-dbg-X11R7.1-1.0.2-r0.tar.gz             wget-locale-et-1.9.1-r6.tar.gz
libxt-dev-X11R7.1-1.0.2-r0.tar.gz             wget-locale-fr-1.9.1-r6.tar.gz
libxt-doc-X11R7.1-1.0.2-r0.tar.gz             wget-locale-gl-1.9.1-r6.tar.gz
libxt6-X11R7.1-1.0.2-r0.tar.gz                wget-locale-he-1.9.1-r6.tar.gz
libz-dbg-1.2.3-r1.tar.gz                      wget-locale-hr-1.9.1-r6.tar.gz
libz-dev-1.2.3-r1.tar.gz                      wget-locale-hu-1.9.1-r6.tar.gz
libz1-1.2.3-r1.tar.gz                         wget-locale-it-1.9.1-r6.tar.gz
minicom-2.1-r0.tar.gz                         wget-locale-ja-1.9.1-r6.tar.gz
minicom-dbg-2.1-r0.tar.gz                     wget-locale-nl-1.9.1-r6.tar.gz
minicom-doc-2.1-r0.tar.gz                     wget-locale-no-1.9.1-r6.tar.gz
ncurses-5.4-r8.tar.gz                         wget-locale-pl-1.9.1-r6.tar.gz
ncurses-dbg-5.4-r8.tar.gz                     wget-locale-pt-br-1.9.1-r6.tar.gz
ncurses-dev-5.4-r8.tar.gz                     wget-locale-ro-1.9.1-r6.tar.gz
ncurses-doc-5.4-r8.tar.gz                     wget-locale-ru-1.9.1-r6.tar.gz
ncurses-terminfo-5.4-r8.tar.gz                wget-locale-sk-1.9.1-r6.tar.gz
ncurses-tools-5.4-r8.tar.gz                   wget-locale-sl-1.9.1-r6.tar.gz
openssl-0.9.7g-r1.tar.gz                      wget-locale-sv-1.9.1-r6.tar.gz
openssl-dbg-0.9.7g-r1.tar.gz                  wget-locale-tr-1.9.1-r6.tar.gz
openssl-dev-0.9.7g-r1.tar.gz                  wget-locale-uk-1.9.1-r6.tar.gz
openssl-doc-0.9.7g-r1.tar.gz                  wget-locale-zh-cn-1.9.1-r6.tar.gz
python-audio-2.4.3-ml0.tar.gz                 wget-locale-zh-tw-1.9.1-r6.tar.gz
python-bsddb-2.4.3-ml0.tar.gz                 xcmiscproto-dev-X11R7.0-1.1.2-r0.tar.gz
python-codecs-2.4.3-ml0.tar.gz                xextproto-dev-X11R7.0-7.0.2-r0.tar.gz
python-compile-2.4.3-ml0.tar.gz               xf86bigfontproto-dev-X11R7.0-1.1.2-r0.tar.gz
python-compiler-2.4.3-ml0.tar.gz              xproto-dev-X11R7.1-7.0.5-r0.tar.gz
python-compression-2.4.3-ml0.tar.gz           xtrans-dev-X11R7.0-1.0.0-r1.tar.gz

Installing the needed packages is just a matter of uncompressing a subset of the above files on the target system.


This exercise demonstrates how a developer can quickly (took me less than 4 hours) add a large number of applications (and dependencies) to about any Embedded Linux system.  Leveraging embedded Linux is being able to use the components you need.  Please contact us if you would like additional details or assistance.


Moxa UC7408 Review

I am currently evaluating a Moxa UC7408 for one of my customers.  The UC7408 is a small fanless industrial computer that runs Linux or Windows CE.  This article provides a basic overview of this unit and a review of some of the UC7408 features and the Linux distribution Moxa provides.


The basic specifications for the UC7408 are:

  • relatively small size and fanless
  • Intel Xscale IXP-422 266MHz Processor
  • 8 RS232/422/485 serial ports
  • 8 digital Input and 8 digital output ports
  • dual 10/100 Ethernet
  • PCMCIA, CompactFlash, Wireless LAN Expansion (supports 802.11b/802.11g)
  • Runs Linux or WinCE
  • Console serial port


The documentation Moxa provides is adequate and fairly detailed.  The moxa documents include a quick install guide, hardware user’s manual, and a 114 page user’s manual.  As good as this documentation is, a general knowledge of Linux is always helpful when working with embedded Linux systems.  Basics like using SSH, FTP, Telnet, and basic Linux system administration are essential when working with embedded Linux.

Linux Distribution

The Linux Distribution provided by Moxa is fairly full featured.  A few highlights with the v1.8 Linux firmware:

  • Provides a 26MB user JFFS2 flash partition.  This partition is read/write and is about 45% full leaving about 14.5MB for user files.  It is probably also possible to delete some of the files that are not required, freeing up more space.
  • Apache & PHP support
  • SSH
  • a number of other utilities are provided such as telnet, ftp, iptables, etc.
  • VI editor
  • Many command line utilities found in most Linux systems.
  • 2.4.18 Kernel

The Linux distribution seems to be based on MontaVista Linux and seems fairly solid.  I ran through some of the basics like mounting a CF card and everything seems to work.

Firmware Updates and Recovery Mode

Moxa provides a mechanism to update the firmware in the system.  This update is a global flash update that programs the entire flash and will erase all user changes.  The update works by enabling a RAM file system and copying the new flash image to the ram file system.  Running an update command that copies the firmware update file into flash.

The 7408 contains a stripped down version of Linux in a separate flash partition that can be booted in a recovery mode if the User flash partition becomes corrupted or unusable.  This mode can be enabled by pressing the “Reset to Default” button on the unit and powering it on.  In this mode, there is no ssh support and you must ftp an image from an ftp server to the device and then reflash it.  This requires you to set up an ftp server that the Moxa system can access.  While this is an entirely workable solution, it may be a challenge for inexperienced Linux users.


Moxa provides a Linux and Windows toolchain to use with the device.  I have built a number of packages with the Linux toolchain and it seems to work well.  It is based on GCC 3.3.2.  Cross compiling applications for embedded Linux is always a challenge and in a future article I will present a way to use OpenEmbedded to compile a number of packages using the Moxa toolchain.

Possible Improvements

There would be some benefits if the system was a little more open in the following areas:

  • access to the bootloader console and documentation.  This would allow developers to more easily flash their own software.
  • readily provide source for GPL components.  Moxa provides a form that you can fill out to receive GPL source code on a CE.  The cost is $100.

One of the big advantages of using Linux in an embedded system is the ability to use the many open source components available.  The easier an embedded solution provider makes this for developers, the more value their system provides.  See the white paper Tips for Planning Your Embedded Linux Project ( for more ideas on this subject.


Overall, the Moxa system seems very usable and the hardware is quite nice.  Stay tuned for future articles about how to get the most out of this system.





Autotools quick reference

At some point, most Linux developers need to master Autotools.  For most of us, this is a fairly painful process, but like any good tool, Autotools is extremely useful and well worth learning.  For example, if your program is set up correctly using Autotools, it will cross compile with almost zero effort in OpenEmbedded, or with slight effort manually.  Compare this to the tedious effort of manually referencing toolchain locations, cross toolchain library and header file locations, etc.  Despite first impressions, Autotools will make your life easier.  This article contains a collection of tips on how to do standard operations using Autotools.

Minimal Autotools files required for a simple C application

AC_INIT([fooprog], [1.0], [])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])


bin_PROGRAMS = foo
foo_SOURCES = foo.c

The above files will create a binary name foo (compiled from foo.c) when you run the following steps:

  • touch NEWS AUTHORS ChangeLog
  • autoreconf -i
  • ./configure
  • make

How to add libraries to the link step

For example, if you want to link in the pthread library to your application, add the following line to

foo_LDADD = -lpthread

How to add compiler options

You can easily add compiler options using the foo_CFLAGS or foo_CPPFLAGS variables.


How to use pkg-config in Autotools

pkg-config is a helper tool that gives you library and include file information for various libraries installed.  For example, to link to alsa and glib in your project:



How to add a command line option to the configure script

    [  --enable-option-foo  help for option foo],

The above example sets a define on the compiler command line if configure is run with the –enable-option-foo command line option.

Disable shared libraries in your project

Add the following to


Pass a variable from to

Often there is a need to pass a variable in to a Makefile.  This is done with the AC_SUBST macro:


foo2 = @VAR_FOO@

Installing data files

By default, Autotools will install executables built when you run “make install”.  To install other non-executable files, you need to tell autotools explicitly about those files.  The standard place to install data files for an application is in $(datadir)/appname.

fooextradir = $(datadir)/@PACKAGE@
fooextra_DATA = \
	foo_data1.txt \

The above will install the foo_data1.txt and foo_data2.txt files in the $(datadir)/fooprog directory. $(datadir) is typically /usr/share/ or /usr/local/share, but it can be anything.

How does my program know where $(datadir) is located

Because $(datadir) can be anywhere in the system, we need some way to tell the program where it was specified to be at time of compilation so that it can locate foo_data1.txt and foo_data2.txt.  This can be done by passing a define at compile time:

AM_CFLAGS = -DDATADIR=\"$(datadir)\"

How to install data files during development without cluttering up my system directories

If you use the above method to install data files needed by your project, you may run into a case during development where you want to run the program from the build directory, but the program needs the data files at run time.  Since, the program is looking for them in the location specified by the DATADIR define, they need to be installed.  You could just run “make install”, but this would install them into /usr/local/share, require you to run as root, and clutter up your system directories.  A much more elegant solution is to specify the install prefix at configure time to be a temporary “install” directory in your source tree.  The –prefix option for configure requires an absolute directory, so the `pwd` trick is used to figure out what the current directory is.

./configure --prefix=`pwd`/install
make install

Your project will now be installed in a directory in your source tree named ./install.  This is also a nice way to test that the install for the project is working correctly as you can easily see everything that gets installed.  Now, the program has been compiled to reference extra files in ./install and will run just fine from the build directory.


The Linux kernel container_of macro

The Linux kernel contains a very useful macro named “container_of” that is used extensively in back-casting a data structure to its containing data structure.  This article includes a simple program that illustrates how this macro is used, and explains why it is so useful.

If you do a lot of C programming, this program is worth figuring out :-).

The program source can also be downloaded from the following location:

/* test code to illustrate use of Linux kernel container_of macro
 * Copyright (c) 2008 Cliff Brake, BEC Systems LLC
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* This program illustrates how the container_of macro works.
 * The container of macro is very useful in multi layered
 * software systems where you have progressivly more detailed
 * software layers.  Below is an example of a bus layer,
 * and then a device layer where a number of different
 * devices might register with the bus.
 * The device registers itself with the bus subsystem, and
 * then the bus subsystem makes a callback into the device.
 * Normally if there are multiple devices registered, the
 * bus subsystem must store and pass a device structure
 * when making callbacks.  With the container_of macro, this is
 * no longer necessary, and the bus subsystem only has to
 * know about one generic device structure, and does not need visibility
 * into lots of different device structures, or do tricks
 * by casting void pointers, etc.  With the container_of macro
 * we can backcast from the generic data structure, to the containing
 * datastructure.  This forces good separation of code in that
 * that bus layer cannot modifiy data structures that are specific
 * to the device layer.

 * (from Linux kernel source)
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:	the pointer to the member.
 * @type:	the type of the container struct this is embedded in.
 * @member:	the name of the member within the struct.
#define container_of(ptr, type, member) ({			\
	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
	(type *)( (char *)__mptr - offsetof(type,member) );})

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

 * BUS layer code

/* generic bus device structure */
struct bus_device
	int general_device_param_a;
	int general_device_param_b;
	void (*device_callback)(struct bus_device * bd);

/* the following is a global list of
 * devices that have registered with the
 * bus subsystem.  Normally this would
 * be something like a dynamic linked list.
struct bus_device * bd_list[5];

/* function to register a device with the bus */
void register_with_bus(struct bus_device * bd)
	/* since this example only deals with one
	 * device, will put it in slot 0

	bd_list[0] = bd;

void start_bus()
	int i;
	struct bus_device * bd;

	/* make callbacks to all devices on bus */
	for (i=0;i<sizeof(bd_list)/sizeof(bd_list[0]);i++) {
		bd = bd_list[i];
		if (!bd) continue;
		/* call device callback with generic
		 * bus device structure

 * device X specific code
 * this would normally be in a different module

/* structure that holds device X specific stuff, as well as
 * generic bus_device structure
struct device_x
	int device_x_specific_param_a;
	int device_x_specific_param_b;
	struct bus_device bd;

void device_x_callback(struct bus_device * bd)
	/* if we know the structure type that contains the bus_device structure,
	 * we can extract a pointer to the containing structure using the container_of
	 * macro

	/*                                   ptr       type       member  */
	struct device_x * devx = container_of(bd, struct device_x, bd);

	/* the above statement expands to
	 * struct device_x * devx = (
	 * {
	 *   const typeof( ((struct device_x *)0)->bd ) *__mptr = (bd);
	 *   (struct device_x *)( (char *)__mptr - ((size_t) &((struct device_x *)0)->bd) );
	 * }
	 * );

	printf("device_x_callback called!, device_x_specific_param_a = %i\n",

void device_x_init()
	/* dynamically allocate structures */
	struct device_x * devx = malloc(sizeof(*devx));
	memset(devx, 0, sizeof(*devx));

	/* set a parameter in the device_x structure so
	 * we can test for this in the callback
	devx->device_x_specific_param_a = 1001;

	/* set up callback function */
	devx->bd.device_callback = device_x_callback;

	/* we register the generic bus device structure
	 * as the bus layer does not need to know
	 * about the device_x stucture.  Note, the
	 * devx structure is not stored anywhere, yet
	 * its location is being preserved without
	 * specifically passing it to the bus
	 * layer.

int main()

	/* test the above system */

	/* first, initialize device_x */

	/* now, start the bus.  This should make
	 * a callback into the device_x

/* when run, this program returns:
 * device_x_callback called!, device_x_specific_param_a = 1001

Gumstix Overo Connector Spreadsheet

One of the first things I do when designing a system based on a processor module is create a spreadsheet listing all the connector I/O.  This is the easiest way I’ve found to make sure nothing gets missed.  My first pass at a I/O spreadsheet for the Gumstix Overo is available at:


GESBC-9302E kernel update to 2.6.24, and reboot fix

I recently updated the GESBC-9302 machine support in OpenEmbedded to include the 2.6.24 released kernel.  Also, Glomation has kindly provided me with a patch for the software reboot problem which I have integrated into the OpenEmbedded build for the GESBC.   The patch files are part of the OpenEmbedded dev branch or can be obtained here:

Other related OpenEmbedded bits:

Future features to be integrated include RTC driver configuration, and support for loading Initramfs images from NOR flash.


Glomation GESBC-9302E Review

Recently, I’ve had the opportunity to work with a Glomation GESBC-9302E single board computer.  This SBC contains a Cirrus Logic EP9302 ARM processor and options for plenty of RAM and Flash memory which means you have many options for writing your applications including high level languages like C# and Python.  In this review, I’ll cover some of basic features of this board and where this board might be useful.

Why the GESBC-9302?

One of the most attractive features of the GESBC-9302E is cost.  The base model with 32MB of RAM, and no NAND flash costs $95 at quantities of 1 unit.  For a model with 64MB of RAM, and 128MB of flash, the cost is $120.  Looking at the board, its simplicity is very evident.  There is basically a CPU, flash, ram, a few linear power supplies, and a very limited amount of support circuitry.  There really is not much to it.


We are helping a customer use the GESBC-9302E in a project where it is functioning as a gateway between a local Zigbee wireless network, and a server located on the internet.  The customer had originally considered using a Linksys NSLU2 for the gateway device during the alpha testing, but upon consideration it seemed like the GESBC-9302E is a better choice in this application for the following reasons:

  • the GESBC does not cost a lot more than a NSLU2
  • you can buy the GESBC with plenty of NAND flash.
  • the GESBC provides two serial ports
  • the GESBC provides many signals on headers than can be used with cables or a daughter card.

Having raw NAND flash on the board is a significant advantage in my opinion.  I’ve run into considerable hassles with consumer grade flash devices in the past (SD, USB Flash, etc).  Although there are industrial grade flash devices, they tend to be more expensive.  My preference at this point for reliable storage in an embedded Linux system is JFFS2 on a 64-128MB raw NAND flash device.  With 128MB of NAND flash, there is plenty of space for a full featured Linux distribution.

With 2 USB ports, plenty of general pupose I/O pins (GPIO), and lots of memory, there is not a lot you can’t do with the GESBC in your typical headless control or gateway type application.  Being able to interface to a number of USB peripherals, and support for high level languages makes this SBC+Linux ideal for implementing a device that may need to talk web services or other complex network protocols.

Software Support

Most of the GESBC functionality is fairly well supported in the mainstream Linux kernel.  Simply configure the kernel for the EDB9302 machine and most things will just work.  There are several pieces missing from the mainstream kernel for the GESBC that are useful: NAND flash support, and a change needed to make the Ethernet work.  For the NAND flash, I extracted a MTD driver from the Glomation kernel source code.  The Ethernet change is a small tweak to the platform files.  These changes are available for the 2.6.24 kernel in a public git repository at:

The GESBC uses Redboot for the bootloader.  No complaints with the bootloader so far — it does everything I need including loading images from a TFTP server.  The bootloader does not support writing images to NAND flash, so to load an OS image into NAND flash you typically have to boot a Linux OS from NOR flash, USB flash, or NFS root, and then use the userspace mtdutils to write an image into NAND flash.

Glomation provides a sample Linux image, but I prefer to use images generated by OpenEmbedded so that I have support for things like C# , Python, and thousands of other packages.  Support for the GESBC has been added to OpenEmbedded and I’m in the process of updating the kernel support to 2.6.24.


Overall I’m very pleased with this SBC.  Glomation has been very responsive to requests and has been a good company to work with. I still need to apply a fix for a known soft reboot issue with the 2.6 kernel and enable a driver for the RTC on the SBC.    Future articles will detail how to load Linux images built with OpenEmbedded on this device.


Compulab EM-X270 Review

The EM-X270 is a full featured computer board from Compulab ( designed for handheld/mobile applications.  The board includes options for about anything you might need in a portable system including a PXA270 processor, GSM radio, GPS, Wifi, Bluetooth, Audio, SD/MMC, USB, battery circuitry, and the list goes on.  The EM-X270 is designed to give you a big head start in designing a handheld computing device, and can significantly reduce time to market and design costs.  This article provides a high level overview of this product, how it might be used, and lots of photos.

EM-X270 Overview

The EM-X270 is a computer board about the size of a display you might find in a typical PDA.  While the size is probably a little large to be used in consumer devices like phones and PDAs, it seems like a nice size for slightly larger products used in vertical industries.


As already mentioned, the EM-X270 includes about all the base features you might need in a mobile computing device.  An expansion connector is also included that allows you to easily add custom circuitry to the system.  The stack-up between the EM-X270 and an expansion board is shown below:


The EM-X270 differers from most other embedded computer modules in that it is a little more application specified, and quite a bit more circuitry is included in the design such as power supplies, battery charging circuitry, radios, etc.

Why EM-X270?

Why are we interested in the EM-X270?  If all you need is a generic handheld computer, there are plenty of options from PDAs to off-the-shelf industrial handhelds.  However, if you need a handheld that provides some additional features not typically found in existing devices, then you can use the EM-X270 plus a custom baseboard and packaging to add your high value features.  Depending what you need to add, the expansion board can be a simple 4 layer board which is very easy to design and manufacture.  All of the complex PCB design and assembly is already done for you on the EM-X270 module.  This allows low to moderate volume manufactures design products where they would not otherwise have the time and budget for designing a full custom processor board.   Some example applications might be handheld products for the medical, industrial, and test and measurement industry.

Compulab’s pricing model is also very interesting.  Compulab will custom build EM-X270 modules with just the options you need.  The base price without any extra features (such as radios) is $122 for 1000 pieces.

The EB-X270 Evaluation Kit

Compulab provides a EB-X270 Evaluation kit for getting started with EM-X270 development.  Like their other Evaluation klits, is is very full featured and very well done.   An extender board is provided that adds Ethernet, JTAG, and several other useful connectors for development.


The eval kit also includes all necessary cables, a display, battery, etc.


Software for the EM-X270

Compulab provides software support for both Windows CE and Linux.  This includes very up-to-date support for kernel version 2.6.23.  EM-X270 machine support has also been included in the OpenEmbedded project for building full featured Linux images.  This combination will drastically reduce development costs compared to solutions provided by many other vendors.  All too often, single board computer vendors provide an ancient kernel, a hacked up root file system and call it a “Linux BSP”.  Actually, any time the term “Linux BSP” is used, you should probably be a bit wary.  A much more attractive solution for those of us building products using Linux is for processor and module vendors to say “our products are supported in the mainstream kernel and OpenEmbedded sources”.  Compulab is doing it right.

OpenEmbedded provides many interesting options for devices like the EM-X270.  One of the most interesting might be the ability to run the OpenMoko software on industrial devices.

Compulab provides a Linux demo image built with OpenEmbedded that runs the GPE Palmtop Environment.  The method for loading this image is interesting, and similar to the method I have been using for some time with systems based on the cm-x270 module ( in that it used mtd-utils from a running Linux system to erase and write to the NAND flash.  The bootloader in the EM-X270 is able to boot a kernel and rootfs directly from a USB Flash disk.  This “LiveDisk” image, as Compulab calls it, contains a small utility that programs an image from the USB flash disk directly into NAND flash.

As with any modern Linux based embedded system, there is a lot going on in a very small package.  Managing this complexity effectively requires some amount of experience.  Stay tuned for future articles that discuss using OpenEmbedded to build software for the EM-X270.

Additional Photos





The Embedded WiFi module Quest

original article written in Sept, 2007

How does one implement WiFi functionality in vertical, low volume portable products?  This is a good question, and one I’ve been struggling with for the past 3 months.  I have a customer who is designing a portable data acquisition system based on a AT91SAM9260 processor, and needs WiFi functionality.  The fundamental problem is that no one has time to deal with low volume customers, and the task of implementing WiFi functionality is obviously complex.  At volumes of 5000 units a year or less, it makes a lot of sense to go with a WiFi module rather than trying to integrate the WiFi chipset on the board.  This article covers some of the options we have looked at and some of the possible solutions.

How is WiFi done on x86 systems?

With desktop Windows, most devices are well supported by device manufacturers.  With x86 Linux some of the devices are well supported by OSS drivers, but these tend to be PCI or USB devices.  Some of the devices that are not supported can still be used by running the Windows NDIS drivers inside of ndiswrapper, which allows you to run the Windows driver on a x86 Linux system, but this obviously does not work very well on non-x86 processors such as ARM.

WiFi solutions for portable, embedded systems

While there are many off-the-shelf solutions for PCs, Notebooks, etc, the current solutions are generally in the USB formfactor.  The ideal solution for portable systems running non-x86 processors are the small modules that connect to the host processor using the SDIO or SPI bus — like the modules you would find in newer cell phones and PDAs.  Older modules tend to use the Compact Flash interface, but these modules tend to be larger and are not packaged as nicely for deeply embedded applications.  So Ideally we want:

  • a modules with a SDIO or SPI interface
  • packaging options such as solder down for robust packaging

The scope of this article is limited to modules that implement a SPI or SDIO interface.  Why are we interested in modules?  Putting a WiFi chip down on a custom PCB is a lot of work.  Because the WiFi silicon includes a processor, if things do not work, it may be very difficult to debug.  There is also the issue of factory calibration which usually requires proprietary PC based tools that can communicate directly with the WiFi silicon.  If the WiFi silicon is buried in your product, getting all this to work can be a challenge.  The test equipment required for calibration is expensive.  Add to this the difficulty in getting support from anyone who makes WiFi silicon …


It should be noted that WiFi modules are fairly complex devices.  They are typically based on a highly integrated IC that includes an ARM processor, Flash memory, and radio circuitry.  The fact that these modules include a significant amount of firmware on the module contributes significantly to the complexity of getting WiFi solutions to work properly.  Hopefully no bugs are encountered in the module firmware, because I can only imagine how difficult it would be to get these fixed for a small customer.   The fact that the module firmware is involved in many of the WiFi functions like authentication further complicates the problem with the abundance of authentication and encryption options available for WiFi.   The worst possible problem is the case where you must design an embedded WiFi system that must operate at the enterprise level in every environment.  It is one thing to design a system that works most of the time in most environments where WiFi is more of a convenience (like a Cell phone or PDA).  It is another thing to design an industrial grade system where it must work all the time and in all environments.

The Fundamental Problems with low volume embedded WiFi

I have never worked with a technology with so many dead ends as embedded WiFi modules.  Many of the companies I email or call never even bother to return emails and phone calls.  This is certainly true of the chipset manufactures.  From what I can gather, the fundamental problems are:

  • WiFi implementation is difficult; therefore, a manufacturer’s scarce resources are dedicated to high volume customers.  Low volume customers are a significant distraction.
  • WiFi companies are very busy right now — they are not hungry for business from small customers.
  • WiFi solutions are very competitive and highly proprietary.  Many companies are very secretive and will not release driver source code.  This is certainly true at the module firmware level.

There are many WiFi module manufacturers and resellers out there, but very few of them offer any type of driver solution for Windows CE or Linux other than binary modules that are supposed to work on perhaps one reference platform.  Sorry, this is not going to cut it.  So, with plenty of hardware available, the gating item is the availability of software drivers and knowledge of how to use the software.  It would seem to me that this is the perfect opportunity for chipset vendors to open source some drivers and develop vibrant support communities so that their modules can be used without a lot of hand-holding by the chipset vendors.

So What are the options?

Atheros AR6001

The Atheros AR6001 seems like a nice solution.  The driver situation for the AR6001 is progressing.  For Windows CE, there is an opensource WinCE 6.0 driver available at:  Unfortunately, this project appears to be a snapshot of code and does not have any significant amount of community activity or development.  Perhaps once more AR6001 modules are available, this will change.

For Linux, there are several options:

  • Atheros has released a driver that is available:  There are several issues with this driver in that it is written for a SDIO stack that will likely never be part of the mainstream kernel.
  • A driver is being developed as part of the OpenMoko project.

Embedded Works supplies Atheros based modules and development boards:    AR6001 development boards are also available from Cardaccess:


The Marvell 88W8385 seems to be a very popular IC in WiFi modules available from a number of different companies.  OSS Linux drivers are in progress and are reportedly somewhat functional at this point, so it is probably just a matter of time before these devices are well supported in Linux.  This chipset/driver is often referred to as “libertas”.  The SDIO stack being developed for the Linux mainline ( is where support for this device is being developed.

For Windows CE, it seems the only option is to get the drivers from Marvell, which is a very difficult and time consuming process — at least for low volume customers.  First you have to find a module reseller that can get you the source code from Marvell, and then the process takes about 3 months.

Other Options

There are a number of other WiFi Silicon manufacturers and module vendors, but the driver options from them seem to be very limited in the form of binary only drivers that will only work with certain processors/operating systems.  As noted before there is almost no hope of getting anyone to even talk with you if your volumes are low.  So your only hope is finding a module vendor that can do any driver work for a NRE fee, obtain the source from the silicon manufacturer, or use OSS drivers.


The Embedded WiFi situation is changing fast, so by the time you read this, it is probably already out of date.  We are currently at the phase where it is very difficult to deeply embedded WiFi in low volume products.  I expect this will change during the next year.  Eventually, WiFi modules re-sellers will figure out that supplying hardware is just one side of the equation.  As things get more and more complex, the software availability and support is becoming the gating item.

Many thanks to James Nahra, Dave Anders, and Erik Strack for sharing information and their WiFi experiences with me over the past few months.


The Embedded Industry Transformation

I just ran across an interesting article written by Doug Gaff titled “Is the embedded industry dead?“. The article points out the transformation that is happening in the “embedded” industry. For many systems, we are no longer constrained by minimal resources ( Embedded Systems are no longer isolated systems, but parts of larger systems.

A few of my own observations:

There is more to modern embedded systems than control and logic. We now have to worry about data. In the past the task might be to get a microcontroller to run a state machine, control motors, etc. Today, we need to present a calendar to the user through a web interface, collect information about the location of the Sun, upload statistics to a remote server, support a rich GUI application on a VGA color display. The control aspect is suddenly the small part of the problem, and managing data is often the primary concern.

Embedded system development now encompasses many disciplines including OS development, web services, advanced application development in high level languages, and the traditional hardware debugging and low level coding tasks. It is becoming less about writing code and more about integration of the right pieces. As Embedded Systems become more complex, access to specialized knowledge is becoming more important. There is just too much for one person (or even one company) to know. Companies developing competitive products in the future will be the ones who have access to experts.
Is your company taking advantage of this transformation?


Compulab cm-x270 PXA270 module review

We are in the process of supporting a customer who is designing a product that uses the Compulab cm-x270 “Computer-on-module”.  The cm-x270 is a small computer module 66x44x7mm that contains an Intel PXA270 ARM processor similar to those found in many PDAs or smart phones.  This review provides an overview of the cm-x270, why it was selected, and how we are using it.

Project Needs

For this project, we needed a low cost embedded computer that could drive a VGA (640×480) color display.  The graphical user interface for the device was fairly advanced, so we were also looking at a system that could run a modern OS with an advanced graphical toolkit.  After discussing the display requirements with the customer, we concluded that we needed a 32-bit processor with a LCD display controller.  As there was some custom circuitry needed, a configuration where the customer could design a custom baseboard and use an off-the-shelf computer module seemed optimal.  The schedule was also very aggressive and we did not have the time or budget to develop a full custom processor board.


After researching a number of computer modules, we chose the cm-x270 from Compulab.  The cm-x270 is a module that includes the following components:

  • Intel PXA270 ARM processor (up to 520Mhz)
  • 802.11b Interface
  • up to 128MB SDRAM
  • 128-512MB NAND flash
  • up to 4MB NOR flash
  • PCI
  • Serial Ports
  • Touch panel controller (UCB1400)
  • Host and Slave USB
  • and other features …

For more details visit the compulab web site (http:// ).  The cm-x270 provides a very impressive number of features in a very small space.

Below is a picture of the cm-x270 mounted on the Compulab SBC-X270 baseboard with a VGA display.  The system is running the GPE Palmtop Environment built with OpenEmbedded.


Low Cost

Perhaps the most impressive feature of the cm-x270 is the cost.  When ordering in volume, Compulab will build the module with only the components you need.  For prototyping, you can order a standard offering with all components populated.  Starting a price of $50, it is the lowest cost module we found.  The configuration we will be using costs around $98 in 2K quantities (64MB DRAM, 4MB NOR Flash, 512MHz + 128MB NAND Flash + Audio/Touchscreen + RTC).  Eventually, we may be able to reduce some of the features and get the price down around $70 per module.

At this price, the cm-x270 provides a very cost effective way to develop a low volume product (a few thousand per year) with advanced features provided by the PXA270 processor.


The bootloader and hardware design of the cm-x270 is proprietary.  Compulab does not supply schematics for the design or source code to the bootloader.  The documentation provided is adequate and provided all the information we needed to complete the design.  Compulab also provides schematics for their development baseboard, which is helpful.


The cm-x270 bootloader provides typical features found in an embedded processor bootloader, including: a serial console, NAND and NOR flash programming, download images from a tftp server, downloading images over a USB connection to a PC, and a number of other configuration commands.  The tftp download works very well and is fast.  The USB download is much slower, but is convenient for systems that do not have a network connection.  The USB download requires a windows PC with a specific version of Microsoft ActiveSync installed, which is unfortunate.  A more general solution that uses something like libusb ( instead of ActiveSync would be preferred as it could then run on both Windows and Linux computers.

Linux Support

Compulab provides a fairly complete port of the 2.6.16 Linux kernel for the cm-x270 in the form of a kernel patch.  Most of the peripherals we tested seem to work with the following exceptions:

  • The SD card driver is not preempt safe.  In this application, we need kernel preemption turned on to meet certain real-time requirements.
  • The Touch driver contains a small bug that does not allow applications using it to exit properly

Overall, support is pretty good and enabled us to get started with development quickly.

NAND Flash Driver

As the Compulab module only provides 4MB of NOR flash, using the NAND flash is a requirement when implementing a full featured Linux system with an advanced graphical user interface.  Compulab provides a binary module that is linked into a kernel driver to support the NAND flash.  This driver provides a block interface on which standard filesystems like ext2 can be used.  The NAND driver has worked fairly well, although we have seen several cases where we get I/O errors if we remove power to the device without shutting down the system properly.  The way to recover is to do a low level format the NAND flash.  This should not be an issue with this product as we will have a backup battery that will be used to power the system during shutdown if power is removed.  We may eventually move to an open source JFFS2 flash driver as time permits.

The proprietary NAND driver presents an additional wrinkle in that the driver cannot be linked into the kernel due to GPL licensing requirements.  One solution is to boot a small root file system from NOR flash that includes the NAND driver module, and then proceed to boot from NAND flash.

GNU/Linux Root File System

Compulab provides an example root file system (I think based on Debian) and suggests using scratchbox to build applications.  We looked at it briefly, but then decided to build our own rootfs using OpenEmbedded for the following reasons:

  • We can easily add additional packages from the extensive OpenEmbedded catalog as needed.
  • Allows us to have an rootfs independent of the module — we can more easily move to other processor modules or architectures in the future.
  • OpenEmbedded provides us with mechanisms for package management and building complete images that include our applications and tweaks to the OS.

For more information on OpenEmbedded, read our “Introduction to OpenEmbedded “.  With OpenEmbedded, we were able to quickly build a toolchain and a root file system that included the kdrive version of Xwindows and GTK+ libraries.  This rootfs fits in less than 32MB of flash disk space, which is much smaller than Compulab’s OS image.

We have also added machine configuration files to the OpenEmbedded project to support the cm-x270:

Design Support

Compulab seems mainly interested in customers who are interested in purchasing modules in volume.  They do not sell low cost development boards such as LogicPD’s $500 board.  Compulab requires you to purchase a fairly high cost development system ($1900) in order to get started.  Part of this cost is to pay for Compulab’s support costs.  For companies who do not have experience designing systems with PXA270 class processors, we highly recommend getting some up-front help from someone who has experience with these systems.  Even though the module takes care of a lot of the design complexity, it helps to have a detailed understanding of the PXA270 and associated components, as you still need to interact with them.  Consulting companies like BEC Systems can provide assistance in the form of hardware design reviews and Linux OS support to accelerate projects and help avoid costly mistakes and delays.  As Compulab designs only the module, there is only so much they can do when you run into problems — as shown in the next section.

Issues Encountered

Overall, the project using the cm-x270 has gone well.  The only real challenge we have faced is a latch-up issue with the ITE PCI controller on the cm-x270 module.  It appears that this part is very sensitive to the characteristics of the 3.3V supply to the module.  After a considerable amount of debugging and testing, we were able to solve this problem with some filtering and slowing down the rise time of the 3.3V supply.  This is a good example of where a project can get difficult very quickly when things don’t work as expected.


So far, the cm-x270 has worked very well in this project.  With its low cost, it is a very attractive option for companies wanting to implement advanced functionality in their products, but don’t have the time, sales volumes, or experience to justify a full processor board design.  Feel free to post comments about your experiences using embedded computer modules.


Do you have an Exit Strategy?

Some time ago, eWeek published in interesting article by Scott McNealy named “Technology’s Barriers to Exit.  In this article, Scott makes an interesting point about considering the cost of technology.  There are three costs to consider:

  • cost of acquisition
  • ongoing cost
  • cost to exit

Scott states that most people analyze the first two costs fairly well.  What is not thought about as much is the the cost to exit — how do I move on to the next thing.  I think these basic questions apply very much to embedded technology decisions.

Most of the time we carefully consider our requirements, think about ongoing manufacturing costs, etc.  There may be some thought given to upgrading (the exit), but we encounter several difficulties when planning for the future with complex embedded systems:

  • we often can’t predict what technologies will be available in the future
  • if may be difficult to predict our product requirements in the future

As an example, we may have a product with an ethernet networking interface, and two years after product launch we have an opportunity that requires a wireless network interface.  How much is it going to cost to add wireless support to our product?  If the product is based on technologies that do not fundamentally support wireless networking, we are looking at very costly exit strategy.  Another example is application-specific, off-the-shelf solutions.  While these are great for many problems and provide a quick way to get something working, what happens when we want to upgrade?  Do we have to re-implement the entire system?

How does one hedge against the unknowns in the future?  One way is to try to anticipate every possible requirement and design it in.  I think this is bad strategy because you usually end up spending a lot of time working on things you don’t really need and the quality of the product suffers.  A better approach is make sure your product does what it needs to do well and is based on a flexible platform where significant parts of your design and software can be re-used in future versions.  This approach has many parallels to recent trends in software development and manufacturing such as Agile Software Development, and Lean Manufacturing.

Follow Scott’s advice and make technology selection decisions with the following questions in mind:

  • Is the technology based on open standards?
  • Are programming interfaces and protocols open, published, and been adopted by industry?
  • Is there a community process behind the technology (not just one company)?
  • Can the same technology be sourced from multiple companies?

The use of Linux in embedded systems is an excellent example of a technology that meets the above criteria.  You can develop your prototype on a x86 PC.  Move it to an embedded ARM single board computer (SBC) for the first production run.  Switch to a different SBC or design your own board when you run into new product requirements.  Sure, it will cost you more to develop the product initially due to the complexity of a system like Linux, but you now have options to expand and change your product while directly re-using the work you have already done.

But wait, as long as I write my application in C, it is portable — right?  Most embedded systems support development in C so I will just port my application to a new platform when needed.  C is a great language and the language is more or less portable between systems.  But as systems get more and more complex, embedded engineers find themselves spending less time writing original code and spending more time putting together pieces that already exist.  A modern embedded application is often little more than some glue between various libraries and system functions.  The fact that you can develop in C for a particular system does not really mean a lot.  What about the threading model, driver model, library APIs, etc.  I just spent a significant amount of time recently porting a large C application from a proprietary platform to new hardware platform as the original system was going obsolete.  It was a huge amount of work.  The driver model was completely different, APIs were different.  Changing platforms can be very expensive.

It rarely pays to be short sighted when choosing technologies for complex embedded systems.  The best strategy is to stay flexible and choose a platform with a future.


Opencores SPI Controller Review

Recently, I had the opportunity to use a SPI controller from Opencores in a customer design based on an Intel PXA255 processor and a Xilinx CPLD.  The customer did not want to change the processor or the CPLD family, but needed an extra SPI interface in the device.  I had my doubts, but mentioned I would look into a SPI controller from Opencores.  To my surprise, the core fit in a Xilinx CPLD and worked out very well.  We have since upgraded to a Altera MAXII CPLD.  This review details this effort.


Embedded is a Service Industry has recently published an article titled: Let’s call Embedded what it is — a Service Industry ( In this article, Curt Schacker discusses how little growth there has been in the Embedded Systems industry. He claims that most embedded companies are trying to establish themselves as product companies, when the market is really a services market. Having worked for two Embedded companies in the past that went out of business, I think he is right. I have often heard the argument that service companies are too much work, they don’t scale, etc. But, to me services has always been a more natural fit for myself and an embedded systems company — one of the reasons BEC Systems exists.