Friday, September 11, 2009

THE SOLUTIONS TO THE REAL TIME SYSTEMS -RTLINUX

INTRODUCTION

One of the most difficult challenges faced by designers of embedded systems is to meet real-time performance requirements. RTLinux introduces many new features that make it an excellent operating system for embedded computing. Among these new features are enhanced real-time performance, easier porting to new computers, support for large memory models, support for microcontrollers, and an improved I/O system. The embedded computing universe includes computers of all sizes, from tiny portable devices, like wristwatch cameras, to systems having thousands of nodes distributed worldwide, as is the case with telecommunications switches. Embedded systems can be simple enough to require only small microcontrollers, or they may use massive parallel processors with prodigious amounts of memory and computing power. RTLinux has been enhanced to provide support across the spectrum of these needs.
WHAT IS REAL-TIME ANYWAY? AND WHO NEEDS IT?

When people talk about real-time, they generally mean "right away" or "fast" as in "real-time stock quotes". A text editor needs to be fast and responsive, but if it's delayed now and then it's no big deal. If a file system averages 100MB/second in data transfer, we don't care if it stops now and then to shuffle buffers. We want things to happen fast (usually described as low-latency). For general-purpose computer systems, "fast" translates to average case performance.

HARD AND SOFT REAL TIMES
But for computer systems, fast doesn't imply real time. A real-time system is one that has deadlines that can't be missed. For example, consider the control of a robot arm that lifts partially assembled automobiles from one assembly station to another. In order to position the arm correctly, the computer must monitor its movement and stop it precisely 5.2 seconds after it starts. These timing constraints make this a hard real-time system, where average case performance won't do--stopping the arm 7 seconds after it starts one time and 3.4 seconds after it starts the next time gets us two expensive and dangerous failures.

Even software that should usually meet timing deadlines, such as video drivers or the X Windows system, can afford a hitch now and then. A missed video frame will not cause the damage of a missed robot arm control message.

So a text editor would ideally (but not necessarily) be fast and responsive (we can tolerate waiting for a while), a video display that can drop a frame now and then needs to usually meet timing deadlines, but a robot controller needs to be able to guarantee meeting deadlines. In the Real-Time Systems literature, the text editor is considered to be "non-real-time" and the video display would be called "soft real-time". Only the robot controller would be called a "hard real-time" system.
.

THE PROBLEM
The problem here is that to deliver the tight worst-case timing needed for hard real-time, operating systems need to be simple, small and predictable. But delivering the sophisticated service that modern applications need is beyond the capabilities of simple, small, predictable operating systems. When you try to put real time inside a general-purpose operating system, or try to put complex services in a small real-time operating system, you end up with something that does neither task well, and where non-real-time services can interfere with the execution of real-time services.

SOLUTION
The solution to this dilemma is to decouple the real-time and non-real-time parts of the operating system. That is, instead of trying to make one operating system support both, we make a system in which a real-time operating system and a general-purpose (time-sharing) system work together. This is the path taken by RTLinux. Instead of trying to create software that combines simplicity with complexity, and combines good worst-case timing with good average-case timing, RTLinux is a small and predictable hard real-time operating system that runs Linux in its idle moments. That is, we put the hard real-time components in a real-time kernel and use Linux to run everything else. The principles that drive the RTLinux design are:

 The core real-time OS needs to be predictable, simple and fast, and have minimal overhead.
 Any process that can go in Linux should go in Linux. A real-time application should be ruthlessly separated into the part that must be real-time and the part that does not have hard-time constraints. The part that doesn't have hard-time constraints should run in Linux.
 Linux operation cannot be permitted to delay the operation of any of the real-time components.

The most powerful result obtained by this scheme is that no matter what Linux does, whether Linux is running in kernel mode or running a user process, whether Linux is disabling interrupts or enabling interrupts, whether Linux is in the middle of a spinlock or not, the real-time system is always able to respond to the interrupt with minimal latency.
RTLINUX STRUCTURE AND PROGRAMMING MODEL
RTLinux is structured as a small core component and a set of optional components.
 The core component permits installation of very low-latency interrupt handlers that cannot be delayed or preempted by Linux itself, and some low-level synchronization and interrupt control routines. This core component has been extended to support SMP, and at the same time it has been simplified by removing functionality that can be provided outside the core.
 The majority of RTLinux functionality is in a collection of loadable kernel modules that provide optional services and levels of abstraction. These modules include: a scheduler, a component to control the system timers, a POSIX I/O layer, real-time FIFOs, and a shared memory module


OUR PROGRAMMING EXAMPLE -A HIGH-SPEED TURBO DYNAMIC APPLICATION

The RTLinux approach to system control gives an incredible degree of flexibility when compared to existing DSP systems. As an example, let's consider in some detail a high-speed turbo dynamic application in which a one-ton rotor is suspended by a five-degree-of-freedom active magnetic bearing (AMB) and spins at 15,000RPM. This application has the following readily identifiable tasks:
1. Five-degree-of-freedom suspension controller. The controller runs at a fixed periodic rate (in the 50--100 microsecond range) and both reads and writes the appropriate signals necessary to suspend the rotor. This task is critical in that missing one sample can have catastrophic consequences.
2. Spin rate measuring task. Triggered once per revolution and used to calculate the spin rate of the rotor. For our rotor, this task will be awakened once every (60/15,000)*1E6 = 4,000 microseconds. The accuracy requirements for the spin rate make this task very intolerant to temporal error.
3. Anti-imbalance controller. Executed 16 times per revolution and is used to produce a synchronous force used to counteract the effect of rotor imbalance--much the same way that balance weights are added to automobile tires to stop them from wobbling. The intertask scheduling period is dependent on the spin rate of the rotor. So, for our rotor, the task would be scheduled once every (4000/16)*1E6 = 250 microseconds. For this task, very slight temporal incorrectness is allowed.
4. Data Datatransfer and data plotting tasks. Used to store data to disk, screen or other devices. These tasks allow relatively large temporal error.
5. Network transfer tasks. Transfer data and commands to and from other computers. For example, the rotor system could be contained in a deep bunker, while the rotor dynamics engineers control it from a safe room some distance away. These tasks allow a larger temporal error.
6. Miscellaneous tasks: such as graphical user interfaces, scripting programs (e.g., Perl and Tcl), and computational engines (Matlab, Scilab, MuPAD, Mathematica, and MathCAD). There is no temporal limitation on these tasks, and they can be performed concurrently with or postmortem to the above tasks.
This entire system can easily be implemented in a single computer using RTLinux, although the standing conventional approach has been to implement each of the above tasks in an independent DSP. In the RTLinux paradigm, the first three tasks would be implemented in the hard real-time environment (RTLinux), while the last three would be comfortably run on the non-RT side (Linux). All can run on the same computer.


Now, let's look at the code. For a sake, we'll focus exclusively on tasks 1 and 2.

Task One--The Suspension Controller

Task 1 can be easily implemented using the POSIX interface. Listing 1 shows the structure as it would be implemented in RTLinux.

Listing 1. Suspension Controller


#include
#include
#include

#define TASK_PERIOD 100000
/* 100 microseconds period */
#define TASK_PRIORITY 1
/* priority assigned to task */

pthread_t thread;

void * task_one(void *arg) {
struct sched_param p;
p . sched_priority = TASK_PRIORITY;

pthread_setschedparam (pthread_self(),
SCHED_FIFO,
&p);
pthread_make_periodic_np (pthread_self(),
gethrtime(),
TASK_PERIOD);

/* startup controller
initialization routine
goes here */
.
.
.

while (1) {
pthread_wait_np();

/* periodic controller
routines go here */
.
.
.
}

return 0;
}

int init_module(void) {
pthread_create (&thread, NULL, task_one, 0);
pthread_setfp_np(&thread,TRUE);
return 0;
}

void cleanup_module(void) {
pthread_cancel (thread);
pthread_setfp_np(&thread,FALSE);
pthread_join (thread, NULL);
}
Here, the init_module() and cleanup_module() functions can be seen as the RTLinux equivalent of the main() function in user-level C programs. Upon startup, the init_module() function is called. This function then immediately tells the scheduler to create a new thread--where the function task_one() comprises the body of the thread--and sets up permissions to enable floating point calculations. Likewise, when the program is stopped, the cleanup_module() function is executed, which in turn stops the thread from further execution, removes permissions to use the floating point unit and quits.

The thread itself can be separated into three segments--initialization, periodic and shutdown--which are represented in the code, respectively, by the segments prior to, inside and after the "while" loop.
First, during initialization, we establish the attributes for this particular thread. We specify the scheduler type to use (SCHED_FIFO), the priority and the frequency at which the thread will be called by the scheduler, and we perform all tasks necessary to initialize our controller.
Next, during the periodic segment, we first encounter the call to pthread_wait_np(), which causes the thread to block until the scheduler calls it again. Thus, the thread will execute the entire contents of the while loop once per execution cycle. Note that in this particular example the shutdown part of our code will never execute, since there is no provision in our example code to exit the while loop. Instead, it will be terminated immediately upon execution of the cleanup_module().

Task Two--Spin Rate Measurement

There are several ways of implementing this second task. In what follows, we shall focus on two: an Interrupt Service Routine running within RTLinux and a signal handler running within a user-level Linux task.

To run Task 2 as an Interrupt Service Routine (ISR), we need to add the following to the code for Task 1 above (assuming that we are using IRQ 7):

#define IRQ 7<\n>
unsigned int example_isr(unsigned int, struct pt_regs *);

unsigned int example_isr(unsigned int irq_number, struct pt_regs *p)
{
/* insert non FP dependent
calculations here */
.
.

rtl_hard_enable_irq(IRQ);
return(0);
}

However, in order to tell RTLinux to associate example_isr() to IRQ 7, we must use the rtl_request_irq() and rtl_hard_enable() functions in init_module():

rtl_request_irq(IRQ, example_isr);<\n>

/* <-- I/O IRQ initialization
routines go here --> */

rtl_hard_enable_irq(IRQ);

The problem becomes more interesting for the implementation of the third task. The thread for Task 3 is created in much the same way as was done for Task 1, however we now use our aforementioned ISR to trigger the first execution of Task 3. The subsequent 15 executions of Task 3 have a period, P, that is dependent on the interarrival times, T, of IRQ 7 as P=T/(16+1).

Our user-level Linux program would use the rtlinux_sigaction() function--first introduced in RTLinux V3.0--to first identify a handler within our program that would be executed each time that IRQ 7 is triggered.

Listing 2. Using the rtlinux_sigaction Function


.
.
.
#include
#define IRQ 7
void my_handler(int);
struct rtlinux_sigaction sig, oldsig;

float old_time=0.0;
float new_time=0.0;
float omega=10.0;
/* spin speed */

int main(void)
{
old_time = ;

/* capture IRQ 7 and execute my_handler
each time that IRQ 7 arrives: */
sig.sa_handler = my_handler;
sig.sa_flags = RTLINUX_SA_PERIODIC;
rtlinux_sigaction( irq, & sig, & oldsig )


/* the main part of our program: we wish to
plot information as long as the rotor is
still spinning */
while(omega>1.0){
sleep(1);
printf("Omega = %.1f\n",omega);
/* to stdout */
plot(old_time,omega);
/* via fancy plotting package*/
}

/* We are no longer spinning,
let's clean up after ourselves... */

/* free the irq: */
sig.sa_handler = RTLINUX_SIG_IGN;
rtlinux_sigaction( IRQ, & sig, & oldsig );

/* exit gracefully */
return 0;
}

void my_handler(int argument)
{
/* calculate spin speed here */
new_time= ;
omega = 1.0/(new_time - old_time);
old_time = new_time;
}

Function

rtlinux_sigaction (), identifies the function my_handler () as the function that we wish to execute each time that IRQ 7 is triggered. "RTLINUX_SA_PERIODIC" tells rtlinux_sigaction () to reset itself and wait for the next signal over and over again--otherwise the signal handler would be executed exactly once. Then the while() loop in our program both prints out and plots the latest spin speed. Finally, when the spin speed drops to below 1Hz, the program begins the shutdown process, which involves the deregistering my_handler() as our signal handler
The job of my_handler() is straightforward: calculate the spin speed. The accuracy of this calculation should be quite high because each time that IRQ 7 is triggered, the handler is called as quickly as the underlying hardware allows.

Regardless of which scheme we use to implement Task 2, the most important thing to note is the amazing versatility and elegance that the RTLinux programming environment provides.









Conclusion

The design compromises that make Linux such a powerful general-purpose OS render it less than ideal for hard and even soft real-time applications. By decoupling real-time and non-real-time processes, RTLinux harnesses the best of both worlds: on the one hand, it offers a high-performance, strictly deterministic real-time application environment, while on the other, it offers the rich programming environment, large application and user base, and powerful networking power of Linux. Most importantly, all improvements made to Linux by its huge development community become instantly available to RTLinux users.

No comments:

Post a Comment