
RGX Real Time Operating Systems
Embedded Electronics Systems
Most software systems are essentially
driven by external real world events such as a key press, a timer tick, or
other device becoming ready for service. Usually, there are large periods of
CPU time spent in polling loops waiting for something to process. If there
are many potential events, the asynchronous nature of the universe tends to
make things happen when it’s least convenient. It’s generally considered
bad form for a software control system to ignore a limit switch input from
a machine in motion, while it processes an array for the machine operator’s
graphics display. There is a solution to the problem.
Interrupts
All modern CPUs have hardware interrupt facilities
that, when activated, force a specialized program jump instruction (CALL). CALL
instructions save the address of the next instruction and jump to a
specified address x. A return instruction (RET) restores the saved address in
the program counter and execution continues from that point. Some CPUs have
special 'return from interrupt' instructions (RETI). The CALL, RET,
Interrupt and RETI functions use STACK memory, who's primary function is to
store return addresses form CALLs and Interrupts. Usually, the STACK memory
area is indirectly addressed by one or more specialized CPU registers, the STACK
pointer.
If our limit switch from the earlier example is connected to
the hardware interrupt input, it can force a ‘stop what your doing and do
this instead’ function. The software system can stop processing the array,
process the machine’s motor off state and return to the array work very
quickly with no effect to that task.
Interrupts and RETI instructions are implemented in different
ways specific to the CPU. Some CPUs make a further distinction to interrupt
time by setting flags enabling 'privileged' mode instructions and some have
multiple stack pointers. Regardless of how it’s done, the big thing it does
for us as system designers is split computer time in two – the time spent
processing an interrupt or background time, and the rest of processing time
or foreground time.
Time Management
Background time is generally controlled by CPU
mechanics but we can use these interrupt properties, some data structures,
and the mechanics of the CPU to write a program that can supervise computer
foreground time, deciding what program runs when and for how long.
As a minimal example, let's say we have two programs.
Program A increments variable x when pushbutton x is pressed. Program B
increments y with button y. Neither program ever tests the other's button.
Pointless, but that's what they do. We want to run both programs on the same
computer. How can we make this work? If we connect a device to the CPU
interrupt that interrupts execution, say every 10 milliseconds, and we give
each program its own stack area in memory, we can alternately stop execution
of one program and start execution of the other every time the interrupt
occurs.
For instance, if program A is running, at interrupt time our
supervisory program runs in background time. It inherits the CPU context of
A. The return address (the address of the next instruction for A) is on A's
stack and the CPU registers are full of the program A's variables. Let's
save all of the CPU registers on the A stack and store the resulting stack
pointer for future reference. The system has been running for awhile, so we
get the previously stored stack pointer for program B, restore the context
from B's stack to the CPU leaving the return address from the previous
interrupt of B on the B stack. When our supervisory program has finished any
bookkeeping it executes a RETI instruction, but the CPU context is restored
for program B which resumes execution as if nothing happened. Since they
switch every 10 milliseconds to us humans they seem to running at the same
time. The example could manage more than 2 programs of course, giving each a
10 millisecond slice of CPU time. This is an example of a time division
operating system.
Real Time Events
Let's get rid of the clock interrupt for now and
connect the pushbuttons to the interrupt with some additional hardware so
the software can determine what button is pushed. We'll change program A and
B so that they call the supervisor code to suspend its operation until its
button is pushed. We'll ad a third program or task that does nothing at all
and never calls the executive, an Idle task, just to soak up the dead time.
Now at interrupt time, the supervisory program stops execution of the idle
task, determines which button caused the interrupt, and starts execution of
the appropriate task which counts and then calls the supervisor to wait
again. This operating system is event driven or "real time". Because the
operating system's response to real world events can be accurately
determined in time and function. This is a deterministic operating system.
Real Time Operating Systems
Actual real time operating systems can control a
number of foreground tasks and offer a variety of services. To be useful for
real time machine control, they must support task prioritization and be
preemptive, run a higher priority task and return to the prior one
seamlessly. They should provide communication between tasks that run in the
foreground time and communication from the background interrupt service
routines (ISR) and the foreground tasks.
RGX Real Time Operating Systems are designed to provide an
efficient set of basic services that can be used to construct high performance
applications with a minimum of code and execution time overhead.