Introduction: a Typical Embedded System
Choosing a filesystem for your embedded system depends on many factors. Do you need to be able to write to it? Do you value size or speed? Do you want to be able to replace the filesystem without replacing the kernel?
You also need to be aware of your storage medium's limitations. For instance, Flash has a limitation when it comes to how many times each cell can be written. To prolong the life of a Flash-based device, it's a good idea to use a filesystem that has been adapted for this purpose.
There are numerous filesystems from which to choose, but the following three are interesting as they show some important factors you should take into consideration:
initramfs: a filesystem that is embedded into the kernel image. If your kernel is compressed, the initramfs filesystem is decompressed alongside the kernel. This gives the system a performance advantage. The filesystem is kept in RAM as the device operates and can be modified. However, all modifications are lost upon reboot.
cramfs/squashfs: two compressed read-only filesystems. Both of these systems let you create a compressed image that you can mount at runtime. The filesystem can be replaced without touching the kernel.
jffs2/ubifs: compressed filesystems tuned for Flash devices. These filesystems can be written to permanently, and they try to minimize the “wear and tear” of the Flash blocks by spreading write operations across the device.
Luckily, you do not have to pick one of these filesystems; instead, you can mix them—for instance, starting from an initramfs image with the most basic tools and then mounting a jffs2 Flash partition for storing user data. As Linux allows you to mount filesystems into any location in your directory tree, you can make this transparent to the applications using the filesystem.
One of the interesting aspects of embedded development is that you are likely to encounter new processor families. Most of you have x86 hardware at home; some might have a SPARC, 68k or a MIPS system lying around. With embedded systems, you are likely to run into ARM, SH, PowerPC or MIPS, among others.
The implication of this is that you must cross compile everything from your desktop build machine (your host machine) for your target device. The resulting binaries cannot be run directly on your desktop machine. You can do it using emulators such as QEMU that allow you to emulate common CPUs, but you will have to do some testing and probably some debugging on your target device.
Sometimes you can get a cross compiler from a vendor or distribution. You also can build your own. Building your own cross compiler used to be a real pain, but these days, you can use crosstool from Dan Kegel. Crosstool is a set of scripts and patches that allows you to build gcc and standard libraries for your platform of choice.
Crosstool's greatest feature is that you can (attempt to) build any combination of compiler and standard library. This makes it easy to try to build a toolchain for an existing device.
Distributions and Frameworks
As fun as it is to roll your own, sometimes time does not permit it. A number of commercial players exist in the embedded Linux field, and many freely developed tools for building a complete embeddable environment also are available. The following list contains a few tools you might consider using:
Buildroot: a set of Makefiles and patches for building a complete embeddable system. It generates everything from the cross compiler, the kernel and software libraries, and the userspace applications. The resulting system uses uClibc.
Ågström distribution: another build framework for building embedded Linux systems. It also sports a package manager. This makes it possible to add and remove applications from the device directly, instead of having to build and download an entire system image or copy the application's files to the right locations manually.
ScratchBox: a build framework for making embedded Linux application development easier. It has gained adoption through the Maemo development platform (the Nokia N7/8/9xx Internet tablets). It supports cross compiling entire distributions, can switch between glibc and uClibc and uses QEMU emulation of targets.
In all of those cases, it takes a bit of work to get the distributions running on a new system. As always with embedded systems, nothing is standardized, and size usually matters, so a bit of tweaking is more or less inevitable. However, having a framework for building a working system can be a real time-saver.
Johan Thelin is a consultant working with Qt, embedded and free software. On-line, he is known as e8johan.