...making Linux just a little more fun!

<-- prev | next -->

Measure CPU Fan Speed with an RTAI/LXRT Stroboscope!

By Pramode C.E.

The BIOS on most modern motherboards will show you the rotational speed of the CPU fan. Let's design a simple ‘optical’ experiment for verifying whether the value reported is indeed correct. For maximum voodoo effect, the experiment should be conducted at night with the only source of light being an LED blinking under the control of some dark and devious RTAI/LXRT code!

What is the big idea?

Think of a fan with four blades rotating at a speed of 3600 rotations per minute (RPM.) Let's mark a part of one of the blades with a distinct color, say white. Once the fan starts rotating, it will be difficult for us to differentiate this blade as everything becomes blurred. Each full rotation takes 1/60th of a second. What if we look at the blades for a very brief period only once in that 1/60th of a second? It will appear as if the white mark is motionless because each time we will see it at almost the same position each revolution. A light source (like an LED) can be made to generate short bursts of light at fairly high frequencies; an object illuminated by such a source will be seen only during those periodic short bursts of light. When the frequency of the bursts match the frequency of rotation of the object being observed, the object appears to be stationary. This is the principle of the stroboscope.

The hardware

There is almost always a cooling fan attached to the CPU in a desktop computer; your only job is to ‘mark’ one of the blades. I did this by pasting a small piece of white paper onto one blade and it seems to work well.

[Editor's note - leaving a high-speed fan unbalanced will shorten the life of its bearings. I strongly advise you to remove the marker from the fan when you are done with the experiment! — dsrich]

The light source is a ‘high-brightness’ LED controlled by the parallel port. It's better that the LED is driven by a transistor other than the parallel port output to increase the amount of current through the LED and therefore its brightness. If you are new to PC interfacing, please proceed with caution, preferably after reading the material presented on web sites such as this one.

The software

Generating small (and precise) time delays under a general purpose operating system like Linux is not an easy job. In one of my earlier articles, I had explained the use of an exciting technology called ‘Real Time Application Interface’ (RTAI) which converts GNU/Linux into a hard real-time OS capable of doing complex timing-sensitive control operations. The trouble with the ‘classical’ RTAI approach was that timing sensitive code had to be written as modules and loaded into the kernel. The more ‘modern’ way of doing things is to use a component of RTAI called LXRT and code real-time tasks as ordinary POSIX threads.

Setting up RTAI/LXRT

RTAI/LXRT is composed of the following:

Here are the steps required to get RTAI/LXRT running on your machine:

  1. Download a a ‘plain’ Linux kernel (from kernel.org) - I used linux-2.6.10.
  2. Download rtai-3.2-test3 from here
  3. When you untar the RTAI source package, you will see several patches under the base/arch/i386/patches directory. Apply the proper patch to your newly downloaded Linux kernel (hal-linux-2.6.10-i386-r9.patch, in case you are using Linux 2.6.10). The patch should apply cleanly.
  4. Configure and compile the kernel. When you configure the kernel, make sure that module versioning support is disabled. The experimental ‘pass parameters in registers’ feature should also be disabled. You can verify both by reading your .config file (after you have done make menuconfig) which should contain the lines:
    
    # CONFIG_REGPARM is not set
    # CONFIG_MODVERSIONS is not set
    
    
  5. Configure and compile rtai-3.2-test3. The configuration and compilation process is fairly simple - you just have to do:
    
    make menuconfig; make; make install
    
    
    When you run make menuconfig, you will be asked to provide the full path to the RTAI-patched Linux kernel source tree. During make install, a few directories will be created under /usr/realtime/ - the header files, libraries and kernel modules required to do RTAI/LXRT development will be found under these directories.
  6. Reboot with the newly compiled kernel. Go to the /usr/realtime/modules directory and try to insert the modules rtai_hal.ko and rtai_lxrt.ko:
    
    cd /usr/realtime/modules/
    insmod ./rtai_hal.ko
    insmod ./rtai_lxrt.ko
    
    
    The modules should load cleanly. Check the output of the program dmesg if there is any problem.

Blinking LEDs

The traditional ‘hello world’ program of the hardware enthusiast is a simple LED blinker. Let's code it as an RTAI/LXRT application:

[Download Listing 1]


/* led1.c, an LXRT LED blinker */

#include <pthread.h>
#include <rtai_lxrt.h>
#include <sys/mman.h>
#include <sys/io.h>

// delay in nanoseconds
#define TICKS 500000000 

main()
{
        RT_TASK *task;
        int priority = 0, i;
        int stack_size = 4096;
        int msg_size = 0; // use default

        // get enough privilege to 
        // access the I/O ports.

        iopl(3);

        task = rt_task_init(nam2num("main"), 
                        priority, stack_size, msg_size);
        if(task == 0) exit(1);
        rt_set_oneshot_mode();
        start_rt_timer(0);
        mlockall(MCL_CURRENT|MCL_FUTURE);
        rt_make_hard_real_time();

        for(i = 0; i < 10; i++) {
                outb(0xff, 0x378);
                rt_sleep(nano2count(TICKS));
                outb(0x0, 0x378);
                rt_sleep(nano2count(TICKS));
        }
        // back to non-rt land!
        rt_make_soft_real_time();
        stop_rt_timer();
        rt_task_delete(task);
        return 0;
}

The rt_task_init function registers our program with the RTAI/LXRT kernel subsystem - the return value is a pointer. Each task should have a name associated with it - we have assigned the name main to our task.

Timing delays in RTAI/LXRT are generated by using the hardware timer chip found on the motherboard. The timer is capable of generating interrupts and can run in two modes - periodic and one shot. When running in periodic mode, it keeps generating interrupts at a fixed rate (say once every 1 millisecond). If all the time delays required in your code can be expressed as multiples of a ‘base’ period (say 1 millisecond), you can think of using the periodic mode. In the ‘one-shot’ mode, the timer will generate just one interrupt at a time after a certain delay. This mode provides more flexibility as the timer can be reprogrammed repeatedly to fire at differing intervals.

The mlockall function is called to disable paging of program memory - paging might result in the program being transferred to persistent swap store medium thereby affecting its real-time behavior.

The rt_make_hard_real_time function transfers control of our application to the RTAI/LXRT realtime scheduler. The effect of this transition is that our code will never get disturbed by normal Linux processes or activities going within the Linux kernel. Note that once the program becomes ‘hard real time’, it should never invoke Linux system calls - doing so will result in the task becoming non real-time.

The nano2count function converts time specified in nanoseconds to some ‘internal count units’ specific to RTAI/LXRT. We have defined TICKS to be 500 milliseconds; so


rt_sleep(nano2count(TICKS))

will suspend our task for half a second. If we run the code with an LED connected to an output pin (pins 2 to 9) of the parallel port, we will see it blinking on and off ten times.

The program should be compiled like this:


cc led1.c -I/usr/realtime/include -L/usr/realtime/lib -lpthread -llxrt

Before running the code, make sure to edit your /etc/ld.so.conf file so that it contains the path to the directory containing the LXRT library (say /usr/realtime/lib); the ldconfig command should also be executed.

The LXRT stroboscope!

I enter the CMOS setup program of my Athlon64 machine and note that my CPU fan is running at a speed of about 3900 rotations per minute, or 65 rotations per second. The time for one rotation is therefore (1000000000/65) nanoseconds, or 15384615 nanoseconds. The idea is to blink an LED connected to pin number 2 of the parallel port at this frequency.


LED on + off time = 15384615 nanoseconds
LED on time = 15384615/12 nanoseconds

Out of the total period of 15384615 nanoseconds, the LED would stay on for (1/12)th of the period and would be off for the remaining time. The fan (and the white paper stuck onto one of the blades) will be visible only during this brief period; by the time the LED is on again, the blade with the paper will have returned back to its original position. Thus, we should be able to see an almost static image of the paper pasted onto the blade.

In practice, I had to continuously tweak the period to get an almost static image. This might be because the fan speed is not remaining constant and keeps on changing slightly.

The code I had written is shown below:

[Download Listing 2]


#include <pthread.h>
#include <rtai_lxrt.h>
#include <sys/mman.h>
#include <sys/io.h>

#define ONE_ROTATION   15384615

volatile int stop = 0;
unsigned int on_time, off_time; 

void* led_task(void *arg)
{
        RT_TASK *task;
        int priority = 0, i;
        int stack_size = 4096;
        int msg_size = 0;

        printf("LED started ...\n");

        task = rt_task_init(nam2num("led"), 
                        priority, stack_size, msg_size);
        if(task == 0) exit(1);
        mlockall(MCL_CURRENT|MCL_FUTURE);
        rt_make_hard_real_time();

        while(!stop) {
                outb(0xff, 0x378);
                rt_sleep(nano2count(on_time));
                outb(0x0, 0x378);
                rt_sleep(nano2count(off_time));
        }
        rt_make_soft_real_time();
        rt_task_delete(task);
        return 0;
}

main()
{
        RT_TASK *task;
        int priority = 10, i;
        int stack_size = 4096;
        int msg_size = 0;
        pthread_t t1;

        on_time = ONE_ROTATION/12;
        off_time = ONE_ROTATION - on_time;

        task = rt_task_init(nam2num("main"), 
                        priority, stack_size, msg_size);
        if(task == 0) exit(1);
        rt_set_oneshot_mode();
        start_rt_timer(0);
        
        pthread_create(&t1, 0, led_task, 0);
        getchar();
        stop = 1;
        pthread_join(t1, 0);
        stop_rt_timer();
        rt_task_delete(task);
        return 0;
}

Note that the main thread is spawning a new thread which calls rt_make_hard_real_time - this is the real-time LED flasher. The main thread remains non real-time because it has to interact with Linux (the getchar function will call the read system call). This is typical of LXRT code; one or more non real-time threads will do all the Linux-interaction part and the hard real-time threads will do some hardware manipulations without invoking any system calls.

Conclusion

As I mentioned in the beginning, do this experiment at night, preferably near around midnight! Whether you see the stroboscopic effect or not, your friends (or family members) who might catch you in action staring at the open motherboard of the machine in pitch darkness with an LED light in your hands are sure to get a very favorable impression about your general geek qualities!

If you have trouble compiling your RTAI patched Linux kernel, you might try using my .config file (Linux 2.6.10, patched with the corresponding RTAI patch.) You should modify the CPU type to match your computer before compilation.

You can learn more about RTAI/LXRT by reading the paper Porting your C++ GNU/Linux application to RTAI/LXRT. The LXRT-Informed FAQ is good reading too. The wikipedia entry on strobe light links the phenomenon to ‘aliasing’ which is common in digital signal processing.

As we are not dealing with sub-millisecond time periods here, the usual Linux delay mechanisms (based on the system clock running at 1KHz on the 2.6 kernel) should be sufficient for this experiment. Doing so is left as an exercise to the reader!

 


[BIO] I am an instructor working for IC Software in Kerala, India. I would have loved becoming an organic chemist, but I do the second best thing possible, which is play with Linux and teach programming!

Copyright © 2005, Pramode C.E.. Released under the Open Publication license unless otherwise noted in the body of the article. Linux Gazette is not produced, sponsored, or endorsed by its prior host, SSC, Inc.

Published in Issue 114 of Linux Gazette, May 2005

<-- prev | next -->
Tux