LinuxDevices.com Archive Index (1999-2012) | 2013-current at LinuxGizmos.com | About  

Article: Whitepaper: Embedding Linux

Jul 26, 2001 — by Rick Lehrbaum — from the LinuxDevices Archive

The evolution of embedded computers

You don't have to go too many years back to recall a time when designing and building embedded systems was a relatively uncomplicated matter. Not that the process was easy — there simply weren't many choices to make. Combine a few inputs and outputs with some time critical components and, voila, you had an embedded system.

As you can imagine, limitations in component choice resulted in functional limitations. Those components available to the design engineer dictated the types of designs the engineer could create, setting off a domino effect that limited overall system performance. Because they were the only kind available for embedded applications, most embedded systems were run with relatively simple 8-bit microcontrollers, the limitations of which forced designers to make significant functional tradeoffs. These limitations, in turn, restricted overall system function and performance. After all, with a slow microcontroller there's no point in adding fast memory. And with only 64KB of available memory, there's only so much the system can do.

Adding a second microcontroller to divide some of the processing load was one solution to the problem, but it was the real-time requirements that drove overall system design and functionality. Limited CPU resources, speed and memory kept multi-tasking to a minimum in order to prevent compromising real-time system response.

On many of these early systems, human interaction was limited to keypads or sensors, which were either polled or interrupt-driven in the system. Outputs were limited to LED indicators or simple serial character displays. These systems were not extremely interesting — or powerful for that matter. These were the days of the 'deeply' embedded devices: relatively simple devices that did not require much human interaction or control. Turn them on and they went to work, sometimes for years at a time.

As more and more powerful CPUs became available to the embedded designer at lower and lower prices, more powerful systems with more features were able to be built, but there was always a sharp divide between what could be used on the traditional desktop computer and what could be run on a small, resource-limited, embedded device.

Now, by combining powerful CPUs with much higher memory densities, this divide is blurring. But consumer demand for more powerful handheld computers, MP3 players with more memory, and two-way pagers with cooler interfaces demands a more complex, multi-tasking operating system that can juggle the load seamlessly, and allow interfacing from a human user just as if the user were a high priority interrupt.

This evolution defines a realm where Linux is the embedded operating system of choice.

Hard Real-Time vs. Soft Real-Time

There is some debate over what constitutes “real-time” operational requirements in any particular system or environment. There is a difference between the real-time requirements of the Mars Polar Lander control system and the real-time requirements of a vending machine.

Strictly speaking, most devices that interact directly with humans are classified as “soft” real-time. There are, of course, exceptions to every rule. For example, a pilot's interaction with the controls of a jumbo jet are certainly “hard” real-time. But if a web page sometimes takes a few more seconds to load, the world will not come crashing to a halt and people will not be hurt. This is the realm of human-interactive embedded devices, and an example of an environment where Linux can be very effective.

Linux is not a real-time operating system, but in many applications, lack of real-time performance is not a deal breaker. Linux tends to be a better fit for devices that are considered 'not-so-deeply' embedded, or devices with relatively high levels of human interaction. Linux is also a robust and reliable player in networking applications.

Let the fun begin

Once a project team has decided on Linux, the fun begins.

Because many ports are available for Linux, it is easier to start with than operating systems that require building upon or modification for the specific application at-hand.

Also, because Linux is open source, the developer has far-reaching debug capabilities — a feature that is often far more valuable then many tech support plans. Many times, issues that arise can be debugged because the developers have all of the source code. Support questions that come up often involve simply pointing developers in the right direction to find the right code to see which control is where in the source tree.

Having source code also gives the development team protection from software problems over which they have no control. Linux provides explicit control over all of the software elements in the project. Any developers who have waited for a vendor to fix an annoying bug in a library understand the real value in having the source code.

The power of networking

Linux was made to run on a network, so for a networked embedded device, it is simply a matter of configuration to turn these modules on, and get the right drivers running to talk to the hardware. There are kernel configuration tools available to the developer, making this task relatively straight-forward. Some of these tools will be discussed later on.

Many of the required drivers have already been written and are available in the open source realm. Some vendors even supply entire development kits which not only contain all of the drivers, but already have the complete development environment integrated so that developers may start immediately with their software implementations.

The network stack is another big portion of the Linux equation. Linux is known for its strong networking performance and robustness. The Linux stack contains essentially the same interface found in Unix. The same socket calls can be made, and useful return and error codes are present. Running a Linux stack pretty much guarantees a compliant stack, and if bugs are found that cannot be resolved in the source by the developer, the community is usually quick to address them. Source availability can be added by the development team if a special networking function needs to be because they have the source code. This means a device can respond in an application-specific manner when prompted by the special initialization packet of the design.

Tailoring Linux to the embedded application

There are three tools in common use for configuring the kernel: make config, make xconfig, and make menuconfig. Each of these tools essentially do the same thing: configure the Linux kernel. Although many applications may be able to forego the process of configuring the kernel, every Linux development effort should, at a minimum, scan the contents of the kernel and classify each element as necessary or not.

Embedded systems must be concerned about overall memory footprint, and trimming the kernel is a great place to start. Only system-essential elements should be present in the kernel. If the embedded device does not have a SCSI interface, then SCSI support should be removed from the kernel.

The first step in configuring the Linux kernel for your specific target is in understanding the directory system used on the Linux development platform. The following subdirectories will be present on most Linux development environments under the top-level directory . . .

    /arch — This directory contains the code that is specific to the architecture. Each supported platform will have its own subdirectory like arch/i386, or arch/armnommu.

    /drivers — this area is further broken out into specific types of drivers, like block, char, cdrom, or scsi. There is a sub-directory for each major type. This is where you would add your own code needed for your specific target.

    /fs — this directory contains all of the support code for file systems like ext2, minix, or even msdos.

    /include — this directory contains all of the needed header files. It is further broken down into architecture specific sub directories, much like the arch directory.

    /init — this optional directory can contain the bootstrap code, which runs when the target is first powered on.

    /kernel — this contains the main kernel code including the scheduler.

    /lib — this contains the architecture specific library code.

    /mm — this directory contains the memory management code.

    /mmnommu — this is the version of the mm directory used for processors that do not contain an mmu, like 68K, or some arm processors.

The kernel build process is not a straightforward process and can get complicated quickly. Since there are so many makefiles and subdirectories and code trees, it is probably easiest to keep the build process automated. Using a script to make sure the build process is done exactly the same way every time is recommended. A script can also make and check the dependencies so the developer can focus on other more interesting parts of the code. In the NetSilicon NET+Works 32-bit RISC product, ported to uCLinux, the kernel build process is automated in this way. The entire build for the kernel is contained in a single build.sh script file. This ensures that every time the build is done, it is done correctly and exactly the same way as before.

Drivers

Usually, it is easiest to find drivers that have already been written and then port them to your target. If the development team has purchased an integrated Linux development environment, such as the NET+Works uCLinux development kit from NetSilicon Inc., the development kit should contain full BSP and drivers for most all components in the hardware. This is the best place to start when doing the development. At a minimum, a provided package should include an Ethernet driver, a couple of different serial drivers, and drivers for whatever other hardware exists on the system.

The sources for these drivers is contained in the arch/drivers directory and are placed according to major grouping, whether they be char drivers, block drivers, or SCSI drivers. Driver code added to a project would most likely go into this directory structure and be added to the driver makefile that would then be built into the kernel using the build.sh script file which builds the entire kernel directory structure.

Memory Requirements

All embedded microprocessor systems must go through the process of defining what the memory requirements of the system will be. Most importantly, how much ROM and RAM are needed in the system. For smaller systems with less functionality, less memory is usually required. It is perhaps one of the more difficult aspects of designing with Linux to determine minimum required memory, but has the single biggest impact on recurring product costs (being that Linux is royalty-free), so it is critical to the final design.

Some designs may be able to run with as little as 256KB of ROM and 512KB of RAM. Much tweaking and snipping will need to be done to develop such a system, and there would likely be little room left for the application or any graphics for web pages. This system would truly be somewhat limited and might not be a good fit for a Linux device.

A more typical memory space is on the order of 2-4 MB of ROM, and 4-8MB of RAM. This system allows for a fully functional kernel with various drivers built in, and a shell program to allow remote users to log into the system. Such a system also becomes a more versatile development platform that can reduce the costs for follow on projects using the same platform.

Is Linux always best?

Linux is certainly rapidly growing in popularity as a software platform for embedded systems and devices. But is it really a good fit for all applications?

The not-so simple answer to this question is a highly-qualified “no.” For the most constrained of devices (with less than a couple of Mbytes of RAM or ROM), it may be larger and more complex than the system can afford. Or, for true “hard real-time” applications, it might not provide the predictability or blazingly fast response times required (although a number of available real-time enhancements and extensions can help a lot).

On the other hand, Linux is an excellent solution for embedded systems and devices that have more than the minimum of resources, are not strictly hard real-time, and have a need for networking or human interaction. Linux is also a great fit when there is a need to take advantage of its open source, royalty-free software model.


Author's bio: William E. Peisel joined NetSilicon in 1987, becoming Vice President of Engineering in 1989 and Chief Technology Officer in 1995. Prior to joining NetSilicon, Peisel was Vice President of Engineering and Director of Engineering at EnMass Computer Corporation, a manufacturer of fault tolerant transaction processing computers, and served as Director of Engineering for Honeywell Information Systems. He holds a B.S.E.E. from Pratt Institute and an M.S.E.E. from Northeastern University.

NetSilicon, a leading provider of integrated hardware and software for Internet/Ethernet connected products, has integrated uClinux and Internet application software with the NET+ARM family of network-enabled microprocessors to create a comprehensive, integrated solution for embedded Linux development.



 
This article was originally published on LinuxDevices.com and has been donated to the open source community by QuinStreet Inc. Please visit LinuxToday.com for up-to-date news and articles about Linux and open source.



Comments are closed.