Cooperative operating systems impose RTOS discipline without its complexity
(For more information on a COS, see the
MiCOS information page!)
Scott Rosenthal
December, 1997
There's nothing like politics, religion and operating systems to get an embedded
designer's mouth foaming. Unlike the first two touchy subjects, when selecting an OS for
an embedded system you can apply some objective rules, which come in handy because the
selected OS matters when shipping a product out the door on time and on budget.
In my experience, operating systems fall into three major categories-monolithic,
realtime and cooperative. From these three classes come every embedded design in use
today. A developer must decide which type of OS a design needs, both for today as well as
several years down the road considering the feature-creep originating from management.
House of cards
The first OS type, monolithic, appears in many embedded designs where I'm called in to
"just add this patch." In fact, the programmers of these systems make no
distinction between the application and the OS. With this house-of-cards approach, the
original designer believes all that's needed are some functions to take data, do a
calculation, display results and loop back on itself. However, a change in one part of the
program probably impacts another part. The program bases measurement timing on the
loop-cycle time through the program.
Admittedly, I've coded this way in the past. The design worked, maybe even made it to
market, but the nagging question of why it worked so well always remained. And forget
about changes! The house-of-cards effect, combined with fading memories of the original
programmer, makes them dangerous. Except for a program or utility with fewer than 100
lines, I won't code this way again.
Fast switching
The realtime OS (RTOS) falls at the opposite extreme from the monolithic system where
the OS isn't separate from the application program. In contrast, with the RTOS, a software
engine runs the show. For anything to happen in the embedded system, application software
must go through the metering actions of the RTOS. These strict interfacing requirements
provide many advantages over a monolithic system. A brief list includes support for
preemptive tasks, task scheduling, conflict handling of system resources as well as
message passing among tasks.
Yet, an RTOS makes a lot of sense in certain applications. One big selling point of
such products is how quickly they can switch from one state or task to another. Thus, if
an application must switch tasks every few hundred microseconds, an RTOS makes a good
choice. Likewise, if you're trying to launch the same piece of code multiple times (for
instance, when additional sensors come on line) an RTOS makes sense.
However, keep in mind some drawbacks to an RTOS. Mastering it is a job unto itself. Ads
talk about how an RTOS implements a hundred or more functionsbut I'm trying to
produce application software, not become an RTOS expert. It can take many hours to become
proficient in using something as simple as a hammerwhere to grip it, the proper arm
extension, the arc to swing it through and hitting a nail square on the head. With
something as complex as an RTOS, I know I have no chance of becoming an expert. Likewise,
each time you switch processors, you must either find a different RTOS or purchase the
same one for the new processor. Further, debugging can become a nightmare with things
happening behind the scenes while you're concentrating on the problem area.
An alternative method
The last type of OS, the cooperative operating system (COS) is a quiet sort of beast.
You don't hear very much about it, but you've most likely used a bloated example of one in
recent years because Windows 3.1 operates on the basis of cooperative multitasking. A COS
relies on the cooperation of your applications to allow a system to function correctly.
Each task or state runs until it no longer has anything to process. Then it returns
control to the COS kernel, which runs the next task or state (Fig 1).
 |
Fig 1A cooperative operating system doesn't have
to worry about preemptiononly event communication and starting routines that run to
completion. |
The implication is that no task in the system should take very long to run. If a task
needs an excessive amount of time, the programmer should split its operation into steps
and execute one step per trip.
Even though Windows 3.1 is quite large, a COS can be very small. My company works with
one that takes only 350 words of code space in a PIC processor or 750 bytes in an X86.
With this small size comes simplicity and a short learning curve, thereby allowing me to
concentrate on the application.
One beauty of a COS or RTOS is that it forces you to design embedded software around an
established guideline, be it simple or complex. As long as you don't try to work around OS
limitations, this imposed structure serves the project well when implementing future
creeping features, training new software staff and debugging.
Table 1COS definitions can differ greatly from their RTOS
counterparts. For instance, in the COS environment a task runs to completion each cycle,
where in an RTOS, it usually starts once and rarely ends.
COS Definitions
|
|
COS |
Cooperative Operating System |
|
Trip |
One complete cycle through the COS |
|
Task |
Module(s) that runs once during the trip |
|
State |
Similar to a task except that only one state
executes per trip. The system is in a specific state at all times |
|
Event |
A message or communication to the tasks and
states |
|
To use a COS, you must break a project down into tasks and states (Table 1). A state is
the system's present mode. For example, Fig 2 shows a fictitious handheld measurement
device with three states: Off, Measure and Standby. The device has one button, a Measure
button, that controls everything. With the device Off, pressing the button starts the
processor running, initializes it, takes a measurement and displays results. A second
button press with the device already on takes another measurement. If you hold the button
down for an extended period or if a timer expires, the device turns itself Off.
The transition from one state to another occurs with events (Fig 2). In the Standby
state, pressing the Measure button exits that state and enters the Measure state. Think
object-oriented programming (OOP) and encapsulation-the Standby state doesn't know how to
handle the Measure button press, but the Measure state does. Programmers generally
describe these state transitions in a table (Table 2). Based on the return flag from the
state, the executive either stays with the same state (FLAG_SAME_STATE) or branches to an
appropriate one.
 |
|
Fig 2A state diagram describes the transition between states in
a visual rather than a tabular form, as is the case with a state transition table (see
Table 2). |
Tasks, in OOP parlance, are like objects. For example, if you're trying to control a
fan's speed based on temperature, the fan becomes a task. Code handles all information
about it (speed, whether On or Off and feedback error checks) within the task. This
isolation means changes to fan code have no influence on other parts of the system.
To manage operation of a system, a COS uses events, which are messages that allow tasks
and states to communicate with each other. Using the fan example, the task that takes the
measurement sends an event (such as EV_TEMP_DONE) to the COS if a new temperature
measurement is available. Each task and state sees this event and acts on it if
appropriate. For instance, if the fan task sees EV_TEMP_DONE, it can adjust fan speed for
the current system temperature. If you later want to add another task to the system such
as data-logging, the new task can also use the event, such as deciding when to save data.
By employing these tasks and events, you don't need to modify existing code, thus reducing
the possibility of problems in the system.
State Transition Table
|
| State ID |
State Entry Point |
State Exit Flag |
Next State |
| STATE_OFF |
stateOff() |
FLAG_MEASURE_CLICK |
STATE_MEASURE |
| STATE_MEASURE |
stateMeasure() |
FLAG_MEASURE_DONE |
STATE_STANDBY |
| STATE_STANDBY |
stateStandby() |
FLAG_MEASURE_CLICK |
STATE_MEASURE |
| STATE_STANDBY |
stateStandby() |
FLAG_MEASURE_HOLD |
STATE_OFF |
| STATE_STANDBY |
stateStandby() |
FLAG_TIMEOUT |
STATE_OFF |
| Table 2The state transition table lists the
transitions that events cause in a system. A designer must ensure that s/he accounts for
all possible events. The state diagram aids this effort greatly. |
Programmers should consider a number of additional advantages of a COS over an RTOS.
One concerns the ease of debugging. Unlike an RTOS, everything in a COS-based system runs
in the foreground. Things don't magically happen in the background. When debugging, you
always know what the software is doing. Also, because a COS runs everything in the
foreground, it's just like any other piece of high-level language software and isn't tied
to a specific processor. You can easily apply what you learn with the COS to many
processors, including PIC, 8051, 68HC11 and Pentium.
Obviously, a COS has its drawbacks, as well. Because the system operation relies on the
cooperation of all pieces of the software, you must write each task's code to relinquish
control. Also, because the trip time through the COS depends on the number of tasks and
what each task and state does, it might be too long for some applications. Based on my
experiences, some applications absolutely require an RTOS because they must process data
quickly, often and at precise times. Yet many don't need the power of an RTOS, and a COS
easily fits the bill. Base your decision on the product's needs and not on hyperbole,
hype, religion or politics. PE&IN
(For more information on a COS, see the
MiCOS information page!)
Adapted from an article that appeared in Personal Engineering & Instrumentation
News.
Return to the article index.
|