SLTF Consulting
Technology with Business Sense



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 functions—but 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 hammer—where 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).

COS Flow

Fig 1—A cooperative operating system doesn't have to worry about preemption—only 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 1—COS 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.

Sample state diagram

Fig 2—A 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
Table 2—The 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!)

Copyright © 1998-2012 SLTF Consulting, a division of SLTF Marine LLC. All rights reserved.