Project 2: Introduction to RTLinux

Real-Time Linux (RTLinux) adds real-time extentions to the normal Linux kernel. It allows us to write hard real-time tasks that can be scheduled with low jitter. For this project we will use RTLinux to generate a signal to control a servo. A servo is an electric motor with an attached control circuit. The control circuit holds the position of the shaft at a fixed angle even if a varying force is applied to the shaft. The angle of the shaft is determined by a digital input.

Servos are used in control applications where a shaft or lever needs to be held at a constant position. The servos we will use for this lab are designed for use with radio-controlled airplanes to move the control surfaces and in radio-controlled cars to control the steering.

The angle of the servo is determined by the width of a pulse on its input. Input pulses must be at least 20 ms apart. The width of the pulse can be from 1 ms to 2 ms. A 1 ms pulse moves the shaft to one end of its range, and a 2 ms pulse moves it to the other end of its range (approximately 180 degrees.) A pulse of approximately 1.5 ms moves the shaft to half way between the two extremes. The figure below shows an example of the timing.

Your job is to write a real-time program that generates a signal to control the servo based on input from a non-real-time program.

Banging the Bits

We could build a simple digital circuit to generate the pulses, but we would still have to interface with the PC and building the circuit would require additional hardware. Instead we'll use a technique, commonly known as bit banging, where the PC directely controls an output bit, making it go high and low at the right times through software.

The easiest way to get a digital signal out of a PC is through the parallel port (see the EE 481 web page or Parallel Port Central for more information on the parallel port). In the PC, I/O devices like the parallel port, are controlled through the processor's I/O space. Each device has several port registers that control the device and report its status. The ports are generally grouped together and referenced in relation to the devices port base address, the port address of the lowest numbered port in the group.

The port registers can be accessed with the inb and outb machine language instructions. The outb instruction writes a byte to a port address, and the inb instruction reads from a port address. Fortunately, including asm/io.h provides wrappers so we can invoke them from a C program. For example, the following C code writes the byte 0x35 to port 0x278:

outb(0x35, 0x278);

From the software perspective, the parallel port looks like three 8-bit registers, Data (D), Status (S), and Control (C). We will concentrate on the D register and not worry about the S and C registers for this project. The parallel parport's port base address is typically 0x378, though it may vary, especially in computers with multiple parallel port interfaces.

Writing a byte to the parallel port port base address sets the bits of the D register, which is output on eight TTL compatible pins on the parallel port. We can turn on or off any combination of the bits by manipulating the bits in a byte, then writing the byte to the D register. RTLinux's threading routines give the means to control the timing of the outb instructions.

Non-Real-Time Interface

The pulse waveform provides low-level control over the servo shaft's angle, but which angle it needs to be in still needs to be determined. For this project we will use a user-level (non-real-time) program to tell the servo which angle it should hold. A user-level program can talk to an RTLinux thread using a FIFO.

From the point of view of the user-level program the FIFO is just a file. The RTLinux FIFO device files are located in /dev/rtfn where n is a number from 0 through 63. A program written in any language can open and close an RTLinux device FIFO just like any other file. For example, in C

if ( (fd = open("/dev/rtf4", O_WRONLY)) < 0) {
perror("open of fifio failed");
exit(-1);
}

opens fifo number 4 and assigns the file descriptor number of the open file to fd or flags an error if the open fails. Once the file is open, the C program can use the normal read and write system calls to read from or write to the file.

The real-time program uses a different interface. The module initialization code should create the FIFO with rtf_create and the module shutdown code should remove the FIFO with rtf_destroy. Any real-time thread can write data to the FIFO with rtf_put or read data from the FIFO with rtf_get. See the RTLinux HOWTO for examples of how to communicate between real-time and non-real-time threads.

For this project the user-level program should write a byte into the FIFO representing the desired position. 0 means the servo should be at one extreme, and 255 means it should be at the other extreme. The module will read the byte from the FIFO to set the servo's position. When the real-time thread gets no input from the user-level program it should simply maintain the servo's current position.

Analysis

If you were to characterize your task using the periodic task model from the book, what are the parameters of your control thread? What is the expression representing the time demanded by your servo control task? Estimate the WCET by measuring the execution time, and add 20% to the worst case time that you measure. Also, assume that a context switch takes 22 µs. Do not forget to include self-suspensions.

What To Submit

When you have completed your project, submit the following through the EE 599 web site:

README
Your README file will contain documentation for you project, including the requested analysis. The format should be ASCII text or PDF.
servoctl.c
servoctl.c is the user-level program that tells the thread controlling the servo what position to go to.
ppservo.c
The ppservo.c file contains the module with the RTLinux thread that writes to the parallel port to control the servo.

In addition to submitting source code and documentation, we will arrange a time after the project has been submitted when you can demonstrate your running program to me. In addition to using your program to control the servo, I may ask you questions about your code during the demo. Be prepared to discuss how any part of your program works.