From the author of

From the author of

In the previous article, I touched upon embedded systems, their uses, and the
importance of developed them in an open manner. Now I'd like to take a
closer look at the technology involved, looking into the specifics of some of
the approaches on the market right now.

Real-time systems have been on the market for years because there has long
been a need for systems to control industrial systems, robotics, and similar
systems. When it comes to controlling hardware on a machine floor, where a
scheduling latency could result in injury or death to those on the floor,
guaranteed scheduling is extremely important. Nearly all systems that interact
with the rest of the world can benefit in some way from some level of real-time
scheduling of operations, and real-time operating systems have been solving
problems in the field for years. Many of these are special-purpose systems that
require developers to work within their specific framework.

These days, Linux has been making large inroads into this market. Whereas you
used to have to write specific code for a specific operating system, today you
can write the code for a general-purpose operating system such as Linux. In many
cases, special real-time systems focused on doing one thingreal-time
servicesand didn't do much else. This means that while you could
perform real-time services, you couldn't easily interact with database
systems, special networking layers, and so on. For many vendors that supplied
these services, it was rarely worth the development effort needed to support
these systems.

With Linux, though, you have a general-purpose operating system with all the
applications and services from a normal Linux environment, plus extensions that
allow you to perform real-time services. Not only does this make application
developers' lives simpler by supporting a smaller group of operating
systems, but it also allows the real-time developer to stay within the normal
UNIX-like environment.

Enough about the bonuses, though. Let's look into how it works. As
mentioned in the previous article, soft and hard real-time status is
achieved through a variety of mechanisms. Some approaches modify the standard
Linux kernel to allow it to be pre-empted. While this approach does allow code
to be run in a more deterministic manner, it depends on direct modifications to
kernel code, albeit restricted to the SMP spinlocks. While this is contained and
relatively simple to keep up-to-date with new releases, it is a moving target.
It is also not perfect with regard to driver bugs, bad locking controls, and
other shifting targets in the Linux development model.

Instead, a dual-kernel approach is being taken up.
RTLinux and
RTAI both use
this mechanism. A real-time system runs on top of the rest of the Linux system,
and the real-time system runs Linux as its lowest-priority thread. This way,
real-time code can be scheduled into the real-time system, and
nonreal-time code can easily be written as a normal userspace application
within Linux itself. This segmentation of logic serves to simplify the problem
into of the real-time code, which runs as a small kernel module, and the rest of
the code, which can be run in userspace. The userspace code is free to use
anything that any other Linux application could use. The kernel modules can
access the real-time API calls and can use Linux kernel calls that don't
depend on locking mechanisms. Communication between the two sides can be done in
a variety of ways, from FIFOs to shared-memory mechanisms.

This dual-kernel approach has been used before with other operating systems,
but applying this concept to non-UNIX systems opens up the door to unneeded
complexities, while at the same time losing the stability and flexibility that
UNIX environments have been providing for years. And because the real-time
component exists as a standalone component, the thread that it runs as a
general-purpose OS doesn't have to be Linux. In the case of RTLinux, the
real-time kernel can run a Linux as a thread or a BSD kernel (or neither, if the
real-time code is all that is needed). Because the real-time component is only
heavy enough to handle a minimal set of operations, overhead is generally found
to be negligible. Also, even worst-case situations are still often near the
hardware limit.

In general, the simplicity of the dual system is difficult to beat. The last
thing that you need when coding for a very fine timing granularity on an
embedded system is the ambiguity of complex infrastructure code. One complaint
is that writing so much kernel code requires more work by the engineer, but now
there exist means for writing real-time code in userspace. Unless this is
needed, however, the division of code between real-time portions and userspace
management is a good idea because it keeps the real-time problems simple and
abstracted out of the rest of the code base.

I'll leave the explicit details of programming within these systems as
an exercise because most of the work involved is a matter of writing the
specific code to control your device. The interfaces for real-time thread
control revolve around the POSIX standard and, as a result, are simple to
understand and use. Keep these systems in mind when you're developing an
embedded system: These days, you can go from a normal, nondeterministic system
to a deterministic, hard real-time OS with very little difficulty, while still
remaining in the comfortable UNIX environment.