BUY THIS BOOK
Add to Cart

Print Book $44.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £31.95

What is this?

Looking to Reprint this content?

Building Embedded Linux Systems
Building Embedded Linux Systems

By Karim Yaghmour
Price: $44.95 USD
£31.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introduction
Since its first public release in 1991, Linux has been put to ever wider uses. Initially confined to a loosely tied group of developers and enthusiasts on the Internet, it eventually matured into a solid Unix-like operating system for workstations, servers, and clusters. Its growth and popularity accelerated the work started by the Free Software Foundation (FSF) and fueled what would later be known as the open source movement. All the while, it attracted media and business interest, which contributed to establishing Linux's presence as a legitimate and viable choice for an operating system.
Yet, oddly enough, it is through an often ignored segment of computerized devices that Linux is poised to become the preferred operating system. That segment is embedded systems, and the bulk of the computer systems found in our modern day lives belong to it. Embedded systems are everywhere in our lives, from mobile phones to medical equipment, including air navigation systems, automated bank tellers, MP3 players, printers, cars, and a slew of other devices about which we are often unaware. Every time you look around and can identify a device as containing a microprocessor, you've most likely found another embedded system.
If you are reading this book, you probably have a basic idea why one would want to run an embedded system using Linux. Whether because of its flexibility, its robustness, its price tag, the community developing it, or the large number of vendors supporting it, there are many reasons for choosing to build an embedded system with Linux and many ways to carry out the task. This chapter provides the background for the material presented in the rest of the book by discussing definitions, real-life issues, generic embedded Linux systems architecture, examples, and methodology.
The words "Linux," "embedded Linux," and "real-time Linux" are often used with little reference to what is being designated. Sometimes, the designations may mean something very precise. Other times, a broad range or category of applications is meant. Let us look at these terms and what they mean in different situations.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Definitions
The words "Linux," "embedded Linux," and "real-time Linux" are often used with little reference to what is being designated. Sometimes, the designations may mean something very precise. Other times, a broad range or category of applications is meant. Let us look at these terms and what they mean in different situations.
Linux is interchangeably used in reference to the Linux kernel, a Linux system, or a Linux distribution. The broadness of the term plays in favor of the adoption of Linux, in the large sense, when presented to a nontechnical crowd, but can be bothersome when providing technical explanations. If, for instance, I say: "Linux provides TCP/IP networking." Do I mean the TCP/IP stack in the kernel or the TCP/IP utilities provided in a Linux distribution that are also part of an installed Linux system, or both? This vagueness actually became ammunition for the proponents of the "GNU/Linux" moniker, who pointed out that Linux was the kernel, but that the system was mainly built on GNU software.
Strictly speaking, Linux refers to the kernel maintained by Linus Torvalds and distributed under the same name through the main repository and various mirror sites. This codebase includes only the kernel and no utilities whatsoever. The kernel provides the core system facilities. It may not be the first software to run on the system, as a bootloader may have preceded it, but once it is running, it is never swapped out or removed from control until the system is shut down. In effect, it controls all hardware and provides higher-level abstractions such as processes, sockets, and files to the different software running on the system.
As the kernel is constantly updated, a numbering scheme is used to identify a certain release. This numbering scheme uses three numbers separated by dots to identify the releases. The first two numbers designate the version, and the third designates the release. Linux 2.4.20, for instance, is version number 2.4, release number 20. Odd version numbers, such as 2.5, designate development kernels, while even version numbers, such as 2.4, designate stable kernels. Usually, you should use a kernel from the latest stable series for your embedded system.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Real Life and Embedded Linux Systems
What types of embedded systems are built with Linux? Why do people choose Linux? What issues are specific to the use of Linux in embedded systems? How many people actually use Linux in their embedded systems? How do they use it? All these questions and many more come to mind when pondering the use of Linux in an embedded system. Finding satisfactory answers to the fundamental questions is an important part of building the system. This isn't just a general statement. These answers will help you convince management, assist you in marketing your product, and most of all, enable you to evaluate whether your initial expectations have been met.
We could use the traditional segments of embedded systems such as aerospace, automotive systems, consumer electronics, telecom, and so on to outline the types of embedded Linux systems, but this would provide no additional information in regard to the systems being designated, because embedded Linux systems may be structured alike regardless of the market segment. Rather, let's classify embedded systems by criteria that will provide actual information about the structure of the system: size, time constraints, networkability, and degree of user interaction.

Section 1.2.1.1: Size

The size of an embedded linux system is determined by a number of different factors. First, there is physical size. Some systems can be fairly large, like the ones built out of clusters, while others are fairly small, like the Linux watch built by IBM. Most importantly, there are the size attributes of the various electronic components of the system, such as the speed of the CPU, the size of the RAM, and the size of the permanent storage.
In terms of size, I will use three broad categories of systems: small, medium, and large. Small systems are characterized by a low-powered CPU with a minimum of 2 MB of ROM and 4 MB of RAM. This isn't to say Linux won't run in smaller memory spaces, but it will take you some effort to do so. If you plan to run Linux in a smaller space than this, think about starting your work from one of the various distributions that put Linux on a single floppy. If you come from an embedded systems background, you may find that you could do much more using something other than Linux in such a small system. Remember to factor in the speed at which you could deploy Linux, though.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Example Multicomponent System
To present and discuss the material throughout the book, this section will examine an example embedded Linux system. This embedded system is composed of many interdependent components, each of which is an individual embedded system. The complete system has a set of fixed functionalities, as seen by its users, but the individual components may vary in composition and implementation. Hence, the example provides us with fertile ground for discussing various solutions, their trade-offs, and their details. Overall, the system covers most types of embedded systems available, from the very small to the very large, including many degrees of user interaction and networking and covering various timing requirements.
The embedded system used as the basis of the examples in this book is an industrial process control system. It is composed of networked computers all running Linux. Figure 1-1 presents the general architecture of the example system.
Figure 1-1: Example embedded Linux system architecture
Internally, the system is made up of four different types of machines, each fulfilling a different purpose: data acquisition (DAQ), control, system management (SYSM), and user interface (UI). The components interconnect using the most common interface and protocol available, TCP/IP over Ethernet. In this setup, the acquisition and control modules sit on a dedicated Ethernet link, while the user interface modules sit on another link. In addition to being the interface between the two links, the system control module provides an interface to the "outside world," which may be a corporate intranet, through a third link.
The process being controlled here could be part of a factory, treatment facility, or something completely different, but this is of no importance to the main design being discussed, because all process control systems have similar architectures. To control a process, the system needs to know at all times the current state of the different components of the process. This is what data acquisition is for. Having acquired the data, the system can determine how to keep the process under control. The location where the analysis is conducted may vary, but all control commands will go out through the control module. Because some aspects of the process being controlled often need human interaction and/or monitoring, there has to be a way for the workers involved to observe and modify the process. This is provided by the various user interfaces. To glue all this together and provide a central data repository and management interface, the system control module is placed at the center of all the components while providing a single access point into the system from the outside world.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Design and Implementation Methodology
Designing and implementing an embedded Linux system can be carried out in a defined manner. The process includes many tasks, some of which may be carried out in parallel, hence reducing overall development time. Some tasks can even be omitted, if a distribution is being used. Regardless of the actual tools or methodology you use, Chapter 2 is required reading for all tasks involved in building an embedded Linux system.
While designing and implementing your embedded Linux system, use the worksheet provided in Appendix A to record your system's characteristics. It includes a section to fully describe each aspect of your embedded system. This worksheet will help your team keep track of the system's components and will help future maintainers understand how the system was originally built. In fact, a properly completed worksheet should be sufficient for people outside your team to rebuild the entire system without any assistance.
Given that the details of the tasks involved in building embedded Linux systems sometimes change with the updating of the software packages involved, visit this book's web site (http://www.embeddedtux.org/) from time to time for updates.
A target Linux system is created by configuring and bundling together the appropriate system components. Programming and development aspects are a separate subject, and are discussed later in this chapter.
There are four main steps to creating a target Linux system:
  • Determine system components
  • Configure and build the kernel
  • Build root filesystem
  • Set up boot software and configuration
Determining system components is like making a shopping list before you go to the grocery store. It is easy to go without a shopping list and wonder at all the choices you have, as many do with Linux. This may result in "featurism," whereby your system will have lots and lots of features but won't necessarily fulfill its primary purpose. Hence, before you go looking at all the latest Linux gizmos available, sit down and write a list of what you need. I find this approach helps in focusing development and avoids distractions such as: "Look honey, they actually have salami ice cream." This doesn't mean that you shouldn't change your list if you see something pertinent. It is just a warning about the quantity of software available for Linux and the inherent abundance of choices.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Basic Concepts
As we saw in the previous chapter, there is a rich variety of embedded Linux systems. There are nevertheless a few key characteristics that apply uniformly to most embedded Linux systems. The purpose of this chapter is to present to you the basic concepts and issues that you are likely to encounter when developing any sort of embedded Linux system.
Many of the subjects introduced here are discussed in far greater detail in other chapters. They are introduced here to give you a better sense of how the entire system comes together.
The chapter starts by discussing the types of hosts most commonly used for developing embedded Linux systems, the types of host/target development setups, and the types of host/target debug setups. These sections are meant to help you select the best environment for developing embedded Linux systems or, if the environment is already specified and can't be changed, understand how your particular setup will influence the rest of your development effort. The chapter then presents details of the structure commonly found in most embedded Linux systems. I present the generic architecture of an embedded Linux system, I explain the system startup, the types of boot configurations, and the typical system memory layout.
In Chapter 3, I cover the hardware most commonly found in embedded Linux targets. Each possible target system can be developed by a wide variety of hosts. In the following, I discuss the types of hosts most commonly used, their particulars, and how easy it is to develop embedded Linux systems using them.
This is the most common type of development host for embedded Linux systems. It is also the one I recommend, because developing embedded Linux systems requires that you become quite familiar with Linux and there is no better way of doing this than using it for your everyday work.
A standard PC is your most likely Linux workstation. Do not forget, nonetheless, that Linux runs on a variety of hardware and that you are not limited to using a PC. I, for example, regularly use an Apple PowerBook running Linux for my embedded work. It lacks an RS232 serial port, but this is easily fixed by adding a USB serial dongle.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Types of Hosts
In Chapter 3, I cover the hardware most commonly found in embedded Linux targets. Each possible target system can be developed by a wide variety of hosts. In the following, I discuss the types of hosts most commonly used, their particulars, and how easy it is to develop embedded Linux systems using them.
This is the most common type of development host for embedded Linux systems. It is also the one I recommend, because developing embedded Linux systems requires that you become quite familiar with Linux and there is no better way of doing this than using it for your everyday work.
A standard PC is your most likely Linux workstation. Do not forget, nonetheless, that Linux runs on a variety of hardware and that you are not limited to using a PC. I, for example, regularly use an Apple PowerBook running Linux for my embedded work. It lacks an RS232 serial port, but this is easily fixed by adding a USB serial dongle.
You may use any of the standard Linux distributions such as Debian, Mandrake, Red Hat, SuSE, or Yellow Dog on your host. In fact, I assume you are running a common distribution throughout this book. As I said in Chapter 1, you do not need an embedded Linux distribution to develop embedded Linux systems. This book provides you with all the necessary information to build your own development environment.
Though I've made an effort to keep the text host-distribution independent, the instructions in this book are slightly tilted towards Red Hat-type distributions. You may therefore need to make minor modifications to a few commands, depending on the distribution installed on your host. Wherever possible, distribution-dependent commands are presented as such.
Of course, the latest and fastest hardware is every engineer's dream. Having the fastest machine around will certainly help you in your work, but you can still use a relatively mild-powered machine with appropriate RAM for this type of development. Remember that Linux is very good at making the best of the available hardware. I, for instance, often use a Pentium II 350MHz system with 128 MB of RAM for development.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Types of Host/Target Development Setups
Three different host/target architectures are available for the development of embedded Linux systems: the linked setup, the removable storage setup, and the standalone setup. Your actual setup may belong to more than one category or may even change categories over time, depending on your requirements and development methodology.
In this setup, the target and the host are permanently linked together using a physical cable. This link is typically a serial cable or an Ethernet link. The main property of this setup is that no physical hardware storage device is being transferred between the target and the host. All transfers occur via the link. Figure 2-1 illustrates this setup.
Figure 2-1: Host/target linked setup
As illustrated, the host contains the cross-platform development environment, which we will discuss in Chapter 4, while the target contains an appropriate bootloader, a functional kernel, and a minimal root filesystem.
Alternatively, the target can use remote components to facilitate development. The kernel could, for instance, be available via Trivial File Transfer Protocol (TFTP). The root filesystem could also be NFS-mounted instead of being on a storage media in the target. Using an NFS-mounted root filesystem is actually perfect during development, because it avoids having to constantly copy program modifications between the host and the target, as we'll see in Section 2.6.
The linked setup is the most common. Obviously, the physical link can also be used for debugging purposes. It is, however, more common to have another link for debugging purposes, as we shall see in Section 2.3. Many embedded systems, for instance, provide both Ethernet and RS232 link capabilities. In such a setup, the Ethernet link is used for downloading the executable, the kernel, the root filesystem, and other large items that benefit from rapid data transfers between the host and the target, while the RS232 link is used for debugging.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Types of Host/Target Debug Setups
There are basically three types of interfaces that developers use to link a target to a host for debugging: a serial line, a networking interface, and special debugging hardware. Each debugging interface has its own benefits and applications. We will discuss the detailed use of some of these interfaces in Chapter 11. This section briefly reviews the benefits and characteristics of each type.
Using a serial link is the simplest way to debug a target from a host, because serial hardware is simple and is often found, in some form or another, in embedded systems. There are two potential problems in using a serial link, however. First, the speed of most serial links is rather limited. Second, if there's only one serial port in the embedded system or if the serial link is the embedded system's only external interface, it becomes impossible to debug the system and interact with it using a terminal emulator at the same time. The absence of terminal interaction is not a problem in some cases, however. When debugging the startup of the kernel using a remote kernel debugger, for example, no terminal emulator is required, since no shell actually runs on the target until the kernel has finished booting.
The use of a networking interface, such as TCP/IP over Ethernet, provides much higher bandwidth than a serial link. Moreover, the target and the host can use many networking connections over the same physical network link. Hence, you can continue to interact with the target while debugging applications on it. You can also debug over a networking link while interacting with the target using a terminal emulator over the embedded system's serial port. However, the use of a networking interface implies the presence of a networking stack. Since the networking stack is found in the Linux kernel, a networking link cannot be used to debug the kernel itself. In contrast, kernel debugging can be and is often carried out over a serial link.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Generic Architecture of an Embedded Linux System
Since Linux systems are made up of many components, let us take a look at the overall architecture of a generic Linux system. This will enable us to set each component in context and will help you understand the interaction between them and how to best take advantage of their assembly. Figure 2-4 presents the architecture of a generic Linux system with all the components involved. Although the figure abstracts to a high degree the content of the kernel and the other components, the abstractions presented are sufficient for the discussion. Notice that there is little difference in the following description between an embedded system and a workstation or server system, since Linux systems are all structured the same at this level of abstraction. In the rest of the book, however, emphasis will be on the details of the application of this architecture in embedded systems.
Figure 2-4: Architecture of a generic Linux system
There are some broad characteristics expected from the hardware to run a Linux system. First, Linux requires at least a 32-bit CPU containing a memory management unit (MMU). Second, a sufficient amount of RAM must be available to accommodate the system. Third, minimal I/O capabilities are required if any development is to be carried out on the target with reasonable debugging facilities. This is also very important for any later troubleshooting in the field. Finally, the kernel must be able to load and/or access a root filesystem through some form of permanent or networked storage. See Section 1.2.1 for a discussion of typical system configurations.
Immediately above the hardware sits the kernel. The kernel is the core component of the operating system. Its purpose is to manage the hardware in a coherent manner while providing familiar high-level abstractions to user-level software. As with other Unix-like kernels, Linux drives devices, manages I/O accesses, controls process scheduling, enforces memory sharing, handles the distribution of signals, and tends to other administrative tasks. It is expected that applications using the APIs provided by a kernel will be portable among the various architectures supported by this kernel with little or no changes. This is usually the case with Linux, as can be seen by the body of applications uniformly available on all architectures supported by Linux.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
System Startup
Three main software components participate in system startup: the bootloader, the kernel, and the init process. The bootloader is the first software to run upon startup and is highly dependent on the target's hardware. As we'll see in Chapter 9, there are many bootloaders available for Linux. The bootloader will conduct low-level hardware initialization and thereafter jump to the kernel's startup code.
The early kernel startup code differs greatly between architectures and will conduct initialization of its own before setting up a proper environment for the running of C code. Once this is done, the kernel jumps to the architecture-independent start_kernel( ) function, which initializes the high-level kernel functionality, mounts the root filesystem, and starts the init process.
I will not cover the details of the kernel's internal startup and initialization, because they have already been covered in detail in Chapter 16 of Linux Device Drivers (O'Reilly). Also, Appendix A of Understanding the Linux Kernel (O'Reilly) provides a lengthy description of the startup of PC-based systems from the initial power-on to the execution of the init process. That discussion covers the kernel's internal startup for the x86.
The rest of the system startup is conducted in user space by the init program found on the root filesystem. We will discuss the setup and configuration of the init process in Chapter 6.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Types of Boot Configurations
The type of boot configuration chosen for a system greatly influences the selection of a bootloader, its configuration, and the type of software and hardware found in the host. A network boot configuration, for example, requires that the host provide some types of network services to the target. In designing your system, you first need to identify the boot configurations you are likely to use during development and in the final product. Then, you need to choose a bootloader or a set of bootloaders that will cater to the different types of boot setups you are likely to use. Not all bootloaders, for example, can boot kernels from disk devices. In the following, I will cover the possible boot configurations. Let us start, nevertheless, by reviewing some boot basics.
All CPUs fetch their first instruction from an address preassigned by their manufacturer. Any system built using a CPU has one form or another of solid state storage device at that location. Traditionally, the storage device was a masked ROM, but flash chips are increasingly the norm today. The software on this storage device is responsible for bootstrapping the system. The level of sophistication of the boot software and the extent to which it is subsequently used as part of the system's operation greatly depends on the type of system involved.
On most workstations and servers, the boot software is responsible only for loading the operating system from disk and for providing basic hardware configuration options to the operator. In contrast, there are very few agreed upon purposes, if any, for boot software in embedded systems because of the diversity in purposes of embedded applications. Sometimes, the boot software will be the very software that runs throughout the system's lifetime. The boot software may also be a simple monitor that loads the rest of the system software. Such monitors can then provide enhanced debugging and upgrading facilities. The boot software may even load additional bootloaders, as is often the case with x86 PCs.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
System Memory Layout
To best use the available resources, it is important to understand the system's memory layout, and the differences between the physical address space and the kernel's virtual address space. Most importantly, many hardware peripherals are accessible within the system's physical address space, but have restricted access or are completely "invisible" in the virtual address space.
To best illustrate the difference between virtual and physical address spaces, let's take a closer look at one component of the example system. The user interface modules, for instance, can be easily implemented on the StrongARM-based iPAQ PDA. Figure 2-6 illustrates the physical and virtual memory maps of an iPAQ running the Familiar distribution. Note that the regions illustrated are not necessarily proportional to their actual size in memory. If they were, many of them would be too small to be visible.
Figure 2-6: Physical and virtual memory maps for the Compaq iPAQ
The physical map of a system is usually available with the technical literature accompanying your hardware. In the case of the iPAQ, the StrongARM manual, the SA-1110 Developer's manual, is available from Intel's web site.
The physical map is important, because it provides you with information on how to configure the kernel and how to develop custom drivers. During the kernel's configuration, for instance, you may need to specify the location of the flash devices in your system. During development, you may also need to write a driver for a memory-mapped peripheral. You will also need to provide your bootloader with information regarding the components it has to load. For these reasons, it is good practice to take the time to establish your system's physical memory map before starting software development.
On the iPAQ, the flash storage is divided in two. The first part contains the bootloader and starts at the lowest memory address available. Given the bootloader's size, this region is rather small. The rest of the flash storage space is occupied by the system's root filesystem, which in the case of Familiar, is a JFFS2 filesystem. In this case, the kernel is actually on the root filesystem. This is possible, because the bootloader has enough understanding of JFFS2 to find the kernel on the filesystem.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Hardware Support
Having covered the basics of embedded Linux systems, including generic system architecture, we will now discuss the embedded hardware supported by Linux. I will first cover the processor architectures supported by Linux that are commonly used in embedded systems. Next, I will cover the various hardware components involved, such as buses, I/O, storage, general-purpose networking, industrial-grade networking, and system monitoring. Although I include many different components, I have omitted components not typically used in embedded configurations.
Note that the following discussion does not attempt to analyze the pros and cons of one hardware component or another. Use it, rather, as a starting point for your research in either identifying the components to include in your system or judging the amount of effort needed to get Linux to run on the hardware you have already chosen.
Also, the following does not cover the software made available by the various hardware vendors to support their hardware. It covers only hardware supported by the open source and free software communities. Some vendors may provide closed-source drivers for their hardware. If you intend to use such hardware, keep in mind that you will have no support from the open source and free software development community. You will have to refer to the vendor for any problems related or caused by the closed-source drivers. Open source and free software developers have repeatedly refused to help anyone that has problems when using closed-source drivers.
Linux runs on a large number of architectures, but not all these architectures are actually used in embedded configurations, as I said above. The following discussion looks at each architecture in terms of the support provided by Linux to the CPUs belonging to that architecture and the boards built around those CPUs. It also covers the intricacies of Linux's support and any possible caveats. I will not cover the MMU-less architectures supported by uClinux, however. Though the code maintained by this project has been integrated late in the 2.5 development series, it remains that the development of the uClinux branch and the surrounding software has its own particularities. If you are interested in an MMU-less architecture to run Linux, you are invited to take a closer look at the uClinux project web site at
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Processor Architectures
Linux runs on a large number of architectures, but not all these architectures are actually used in embedded configurations, as I said above. The following discussion looks at each architecture in terms of the support provided by Linux to the CPUs belonging to that architecture and the boards built around those CPUs. It also covers the intricacies of Linux's support and any possible caveats. I will not cover the MMU-less architectures supported by uClinux, however. Though the code maintained by this project has been integrated late in the 2.5 development series, it remains that the development of the uClinux branch and the surrounding software has its own particularities. If you are interested in an MMU-less architecture to run Linux, you are invited to take a closer look at the uClinux project web site at http://www.uclinux.org/. uClinux currently supports Motorola MMU-less 68K processors, MMU-less ARM, Intel's i960, Axis' Etrax, and other such processors.
The x86 family starts with the 386 introduced by Intel in 1985 and goes on to include all the descendants of this processor, including the 486 and the Pentium family, along with compatible processors by other vendors such as AMD and National Semiconductor. Intel remains, though, the main reference in regards to the x86 family and is still the largest distributor of processors of this family. Lately, a new trend is to group traditional PC functionality with a CPU core from one of the 386 family processors to form a System-on-Chip (SoC). National Semiconductor's Geode family and ZF Micro Devices' ZFx86 are part of this SoC trend.
Although the x86 is the most popular and most publicized platform to run Linux, it represents a small fraction of the traditional embedded systems market. In most cases, designers prefer ARM, MIPS, and PowerPC processors to the i386 for reasons of complexity and overall cost.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Buses and Interfaces
The buses and interfaces are the fabric that connects the CPU to the peripherals that are part of the system. Each bus and interface has its own intricacies, and the level of support provided by Linux to the different buses and interfaces varies accordingly. The following is a rundown of the buses and interfaces found in embedded systems and a discussion of their support by Linux. Linux supports many other buses, such as SBus, NuBus, TurboChannel, and MCA, but these are workstation or server-centric.
The Industry Standard Architecture (ISA) bus was designed for and occupied the core of PC-AT architecture. It was odd even for its time, as it did not provide many of the facilities other buses offered, including ease of mapping into normal processor physical address space. Its simplicity, however, favored the proliferation of many devices for the PC, which, in turn, favored the use of PCs in embedded applications.
ISA devices are mostly accessed through the I/O port programming already available in the x86's instruction set. Therefore, the kernel does not need to do any work to enable device drivers to use the bus. Instead, the various device drivers access the appropriate I/O ports directly using the in/out assembly functions. Although the kernel provides support for Plug and Play (PNP) devices, this capability is of little use for embedded applications. Instead, embedded systems that do need to support hardware variations will be based on buses that support runtime hardware addition and removal, such as CompactPCI, PCMCIA, and USB. The kernel also supports Extended ISA (EISA) devices, but this bus has not been very popular and has been superseded by the PCI bus.
Information regarding the ISA bus can be found in many places. The PC Handbook and HelpPC mentioned above are good quick references for port numbers and their operation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
I/O
Input and output (I/O) are central to the role of any computerized device. As with other OSes, Linux supports a wide range of I/O devices. The following does not pretend to be a complete run-down of all of them. For such a compilation, you may want to read through the Hardware Compatibility HOWTO available from LDP. Instead, the following concentrates on the way the different types of I/O devices are supported by Linux, either by the kernel or by user applications.
Some of the I/O devices discussed are supported in two forms by the kernel, first by a native driver that handles the device's direct connection to the system, and second through the USB layer to which the device may be attached. There are, for instance, PS/2 keyboards and parallel port printers and there are USB keyboards and USB printers. Because USB has already been discussed earlier, and in-depth discussion of Linux's USB stack would require a lengthy text of its own, I will cover only the support provided by Linux to the devices directly attached to the system. Note, however, that USB drivers for similar devices tend to rely on the infrastructure already available in Linux to support the native devices. A USB serial adapter driver, for example, relies on the same facilities as the traditional serial driver, in addition to the USB stack.
The serial port is arguably every embedded system developer's best friend (or her worst enemy, depending on her past experience with this ubiquitous interface). Many embedded systems are developed and debugged using an RS232 serial link between the host and the target. Sometimes, PCBs are laid out to accommodate a serial port, but only development versions of the boards ever include the actual connector, while production systems are shipped without it. The simplicity of the RS232 interface has encouraged its wide-spread use and adoption, even though its bandwidth is rather limited compared to other means of transmission. Note that there are other serial interfaces besides RS232, some of which are less noise-sensitive and therefore more adapted to industrial environments. The hardware serial protocol, however, isn't as important as the actual programming interface provided by the serial device's hardware.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Storage
All embedded systems require at least one form of persistent storage to start even the earliest stages of the boot process. Most systems, including embedded Linux systems, continue to use this same initial storage device for the rest of their operation, either to execute code or to access data. In comparison to traditional embedded software, however, Linux's use imposes greater requirements on the embedded system's storage hardware, both in terms of size and organization.
The size requirements were discussed in Chapter 1, and an overview of the typical storage device configurations was provided in Chapter 2. We will discuss the actual organization further in Chapter 7 and Chapter 8. For the moment, let us take a look at the persistent storage devices supported by Linux. In particular, we'll discuss the level of support provided for these devices and their typical use with Linux.
In Linux terminology, memory technology devices (MTDs) include all memory devices, such as conventional ROM, RAM, flash, and M-Systems' DiskOnChip (DOC). As explained by Michael Barr in Programming Embedded Systems in C and C++ (O'Reilly), such devices have their own capabilities, particularities, and limitations. Hence, to program and use an MTD device in their systems, embedded system developers traditionally use tools and methods specific to that type of device.
To avoid, as much as possible, having different tools for different technologies and to provide common capabilities among the various technologies, the Linux kernel includes the MTD subsystem. This provides a unified and uniform layer that enables a seamless combination of low-level MTD chip drivers with higher-level interfaces called user modules, as seen in Figure 3-1. These "user modules" should not be confused with kernel modules or any sort of user-land software abstraction. The term "MTD user module" refers to software modules within the kernel that enable access to the low-level MTD chip drivers by providing recognizable interfaces and abstractions to the higher levels of the kernel or, in some cases, to user space.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
General Purpose Networking
An increasing number of embedded systems are attached to general purpose networks. These devices, although more constrained than other computerized systems in many ways, are often expected to provide the very same network services found in many modern servers. Fortunately, Linux lends itself quite well to general purpose networks, since it is itself often used in mainstream servers.
The following discussion covers the networking hardware most commonly found in embedded systems. Linux supports a much wider range of networking hardware than I will discuss, but many of these networking interfaces are not typically used in embedded systems and are therefore omitted. Also, as many of these networking interfaces have been extensively covered elsewhere, I will limit the discussion to the topics relevant to embedded Linux systems and will refer you to other sources for further information.
Network services will be discussed further in Chapter 10.
Initially developed at Xerox's PARC research center in Palo Alto, California, Ethernet is currently the most pervasive, best documented, and least expensive type of networking available. Its speed has kept up with the competition, growing geometrically over the decades. Given Ethernet's popularity and the increasing demand for embedded systems to be network enabled, many embedded development boards and production systems have been shipping with Ethernet hardware.
Linux supports a slew of 10 and 100 Megabit Ethernet devices and chips. It also supports a few Gigabit Ethernet devices. The kernel build configuration menu is probably the best place to start to see whether your particular hardware is supported, since it contains the latest drivers list. The Ethernet HOWTO, available from the LDP, also contains a list of supported hardware, and a lot of information regarding the use of Ethernet with Linux. Finally, Donald Becker, who wrote quite a few Linux Ethernet drivers, maintains a web site with information regarding Linux's network drivers at
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Industrial Grade Networking
As with other computerized applications, industrial control and automation rely increasingly on computerized networks. General-purpose networking or connectivity solutions such as plain Ethernet or Token Ring are, however, ill-adapted to the harsh and demanding environment of industrial applications. Common Ethernet, for instance, is too vulnerable to EMI (Electromagnetic Interference) and RFI (Radio Frequency Interference) to be used in most industrial environments.
Therefore, quite a few specialized, industrial-grade networking solutions have been developed over time. In addition to being more adapted to industrial environments, these industrial networks, commonly known as fieldbuses, contribute to reducing wiring, increasing modularity, providing diagnostics capabilities, enabling self-configuration, and facilitating the setup of enterprise-wide information systems.
In the following sections, I will cover the industrial networks supported by Linux and briefly discuss the other industrial networks that have little or no Linux support. If you are new to fieldbuses, you may want to take a look at Rob Hulsebos' Fieldbus Pages located at http://ourworld-top.cs.com/rahulsebos/. The web site includes a large collection of links and references to all sorts of fieldbus systems.
The Controller Area Network (CAN) is not only the most common fieldbus, but probably one of the most pervasive forms of networking ever used. CAN was introduced in 1986 by Robert Bosch Gmbh. as a serial bus system for the automotive industry and has since been put to use in many other industries. CAN's development received early contributions from engineers at Mercedes-Benz and Intel, which provided the first CAN chip, the 82526. Today, more than 100 million new CAN devices are sold every year. Application fields range from upper-class cars, such as Mercedes, to factory automation networks.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
System Monitoring
Both hardware and software are prone to failing, sometimes drastically. Although the occurrence of failures can be reduced through careful design and runtime testing, they are sometimes unavoidable. It is the task of the embedded system designer to plan for such a possibility and to provide means of recovery. Often, failure detection and recovery is done by means of system monitoring hardware and software such as watchdogs.
Linux supports two types of system monitoring facilities: watchdog timers and hardware health monitoring. There are both hardware and software implementations of watchdog timers, whereas health monitors always require appropriate hardware. Watchdog timers depend on periodic reinitialization so as not to reboot the system. If the system hangs, the timer eventually expires and causes a reboot. Hardware health monitors provide information regarding the system's physical state. This information can in turn be used to carry out appropriate actions to signal or solve actual physical problems such as overheating or voltage irregularities.
The kernel includes drivers for many watchdog timers. The complete list of supported watchdog devices can be found in the kernel build configuration menu in the Watchdog Cards submenu. The list includes drivers for watchdog timer peripheral cards, a software watchdog, and drivers for watchdog timers found in some CPUs such as the MachZ and the SuperH. Although you may want to use the software watchdog to avoid the cost of a real hardware watchdog, note that the software watchdog may fail to reboot the system in some circumstances. Timer watchdogs are seen as /dev/watchdog in Linux and have to be written to periodically to avoid system reboot. This updating task is traditionally carried out by the watchdog daemon available from ftp://metalab.unc.edu/pub/linux/system/daemons/watchdog/. In an actual embedded system, however, you may want to have the main application carry out the update instead of using the watchdog daemon, since the latter may have no way of knowing whether the main application has stopped functioning properly.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Development Tools
Much like mainstream software developers, embedded system developers need compilers, linkers, interpreters, integrated development environments, and other such development tools. The embedded developer's tools are different, however, in that they typically run on one platform while building applications for another. This is why these tools are often called cross-platform development tools, or cross-development tools, for short.
This chapter discusses the setup, configuration, and use of cross-platform development tools. First, I will discuss how to use a practical project workspace. I will then discuss the GNU cross-platform development toolchain, the C library alternatives, Java, Perl, Python, Ada, other programming languages, integrated development environments, and terminal emulation programs.
In the course of developing and customizing software for your target, you will need to organize various software packages and project components in a comprehensive and easy-to-use directory structure. Table 4-1 shows a suggested directory layout you may find useful. Feel free to modify this structure to fit your needs and requirements. When deciding where to place components, always try to find the most intuitive layout. Also, try to keep your own code in a directory completely separated from all the packages you will download from the Net. This will minimize any confusion regarding the source's ownership and licensing status.
Table 4-1: Suggested project directory layout
Directory
Content
bootldr
The bootloader or bootloaders for your target
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using a Practical Project Workspace
In the course of developing and customizing software for your target, you will need to organize various software packages and project components in a comprehensive and easy-to-use directory structure. Table 4-1 shows a suggested directory layout you may find useful. Feel free to modify this structure to fit your needs and requirements. When deciding where to place components, always try to find the most intuitive layout. Also, try to keep your own code in a directory completely separated from all the packages you will download from the Net. This will minimize any confusion regarding the source's ownership and licensing status.
Table 4-1: Suggested project directory layout
Directory
Content
bootldr
The bootloader or bootloaders for your target
build-tools
The packages and directories needed to build the cross-platform development toolchain
debug
The debugging tools and all related packages
doc
All the documentation you will need for your project
images
The binary images of the bootloader, the kernel, and the root filesystem ready to be used on the target
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
GNU Cross-Platform Development Toolchain
The toolchain we need to put together to cross-develop applications for any target includes the binary utilities, such as ld, gas, and ar, the C compiler, gcc, and the C library, glibc. The rest of the discussion in the later chapters relies on the cross-platform development toolchain we will put together here.
You can download the components of the GNU toolchain from the FSF's FTP site at ftp://ftp.gnu.org/gnu/ or any of its mirrors. The binutils package is in the binutils directory, the gcc package is in the gcc directory, and the glibc package is in the glibc directory along with glibc-linuxthreads. If you are using a glibc version older than 2.2, you will also need to download the glibc-crypt package, also from the glibc directory. This part of the library used to be distributed separately, because U.S. cryptography export laws made it illegal to download this package to a computer outside the U.S. from the FSF's site, or any other U.S. site, for that matter. Since Version 2.2, however, glibc-crypt has been integrated as part of the main glibc package and there is no need to download this package separately anymore. Following the project directory layout suggested earlier, download the packages into the ${PRJROOT}/build-tools directory.
Note that all the targets discussed in Chapter 3 are supported by the GNU toolchain.
Configuring and building an appropriate GNU toolchain is a complex and delicate operation that requires a good understanding of the dependencies between the different software packages and their respective roles. This knowledge is required, because the GNU toolchain components are developed and released independently from one another.

Section 4.2.1.1: Component versions

The first step in building the toolchain is selecting the component versions we will use. This involves selecting a binutils version, a gcc version, and a glibc version. Because these packages are maintained and released independently from one another, not all versions of one package will build properly when combined with different versions of the other packages. You can try using the latest versions of each package, but this combination is not guaranteed to work either.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
C Library Alternatives
Given the constraints and limitations of embedded systems, the size of the standard GNU C library makes it an unlikely candidate for use on our target. Instead, we need to look for a C library that will have sufficient functionality while being relatively small.
Over time, a number of libraries have been implemented with these priorities in mind. In the following, we will discuss the two most important C library alternatives, uClibc and diet libc. For each library, I will provide background information, instructions on how to build the library for your target, and instructions on how to build your applications using the library.
The uClibc library originates from the uClinux project, which provides a Linux that runs on MMU-less processors. The library, however, has since become a project of its own and supports a number of processors that may or may not have an MMU or an FPU. At the time of this writing, uClibc supports all the processor architectures discussed in depth in Chapter 3. uClibc can be used as a shared library on all these architectures, because it includes a native shared library loader for each architecture. If a shared library loader were not implemented in uClibc for a certain architecture, glibc's shared library loader would have to be used instead for uClibc to be used as a shared library.
Although it does not rely on the GNU C library, uClibc provides most of the same functionality. It is, of course, not as complete as the GNU library and does not attempt to comply with all the standards with which the GNU library complies. Functions and function features that are seldom used, for instance, are omitted from uClibc. Nevertheless, most applications that can be compiled against the GNU C library will also compile and run using uClibc. To this end, uClibc developers focus on maintaining compatibility with C89, C99, and SUSv3. They regularly use extensive test suites to ensure that uClibc confo