VMITMRF: GE Fanuc Timer Driver

Contents:

Abstract
Installation
Loading and Unloading the Module
Writing Applications Using the VMITMRF Driver
Using the Timer Driver

Abstract

The vmitmrf driver is a loadable Linux device driver module for GE Fanuc single board computers (SBCs) with a GE Fanuc FPGA timer device. SBCs currently supported by this driver include:

  • VMICPCI-7753
  • VMICPCI-7755
  • VMICPCI-7756
  • VMICPCI-7757
  • VMIVME-7700
  • VMIVME-7750
  • VMIVME-7751
  • VMIVME-7765
  • VMIVME-7766
  • VMIVME-7805
  • VMIVME-7807
  • VMIVME-7810

This list may not be complete. If your board is not listed please contact GE Fanuc Customer Care to confirm support.

This document describes installation and usage of the vmitmrf timer driver for GE Fanuc SBCs.

This document assumes that you have some knowledge of the Linux operating system and C programming for POSIX/UNIX machines.

Installation

Building

Warning: Linux kernel source code must be installed to build the driver module.

To use the vmitmrf driver, it must first be compiled (built) into executable code and installed. The next code listing illustrates how to compile and install the vmitmrf driver.

Code listing 1: Compiling and Installing the VMITMRF Driver

// From the vmitmrf base directory execute:
sh$ make
sh# make install

Verifying the Installation

If the project is built and installed correctly, you should have the following files installed on your system:

Code listing 2: Verify the Installation

// This is the driver module.  Make sure you use `uname -r`, not 'uname -r'.
sh$ ls /lib/modules/`uname -r`/extra/
vmitmrf.ko
// This header file contains the ioctl calls and others macros
sh$ ls /usr/include/linux/hwtimer.h
hwtimer.h
// These are the device files used to access the timer devices
sh$ ls -l /dev/timer*
crw-rw-rw-    1 root     root     231,   1 Sep 12 01:43 /dev/timer1
crw-rw-rw-    1 root     root     231,   2 Sep 12 01:43 /dev/timer2
crw-rw-rw-    1 root     root     231,   3 Sep 12 01:43 /dev/timer3
crw-rw-rw-    1 root     root     231,   4 Sep 12 01:43 /dev/timer4

Warning: The major device number 231 is not allocated within the official device list. This number could change or be in conflict with another device at some time in the future. The major device number used can be changed in the Makefile by modifying the definition DEVMAJOR:=231.

Loading and Unloading the Module

Use the modprobe command to load the driver module by entering modprobe vmitmrf.

Use the lsmod command command to verify that the module loaded successfully. When you enter lsmod, the module name vmitmrf should appear in the output.

To unload the module, enter modprobe -r vmitmrf.

Writing Applications Using the VMITMRF Driver

The vmitmrf driver supports the following standard Linux system calls:

  • open
  • close
  • read
  • write
  • select
  • ioctl

Code listing 3: Writing an application that uses the timers

// Here is some test code that demonstrates use of the timer.
// This source code is included in the test directory.
// The file is called tmr_example.c


#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/hwtimer.h>
#include <sys/ioctl.h>


/*===========================================================================
 * Main routine
 */
int main()
{
        const int buffer_size = 0x100000;
        int fd3, fd4, count, rate, ii, start_count, end_count;
        char src[buffer_size], dest[buffer_size];
        fd_set fds;

        if (-1 == (fd3 = open("/dev/timer3", O_RDWR))) {
                perror("open");
                return -1;
        }

        if (-1 == (fd4 = open("/dev/timer4", O_RDWR))) {
                perror("open");
                return -1;
       }

        /* Set up the file descriptor we are going to poll for interrupts on.
         */
        FD_ZERO(&fds);
        FD_SET(fd3, &fds);

        /* Set up timer 3 to cause a periodic interrupt every second.
         */
        rate = 1000;
        count = 1000000;
        ioctl(fd3, TIMER_RATE_SET, &rate);
        write(fd3, &count, sizeof (count));
        ioctl(fd3, TIMER_INTERRUPT_ENABLE);
        ioctl(fd3, TIMER_START);

        /* Set timer 4 for 1Mhz
         */
        ioctl(fd4, TIMER_RATE_SET, &rate);

        /* Copy some data every second for 5 iterations. Measure the
           time it took to complete the memcpy for each iteration.
         */
        printf("Copying %d bytes\n", buffer_size);
        start_count = 0xffffffff;
        for (ii = 1; ii <= 5; ++ii) {
                /* Use select to poll for an interrupt.
                 */
                select(fd3 + 1, NULL, NULL, &fds, NULL);

                /* Write an initial count and start the timer.
                 */
                write(fd4, &start_count, sizeof (start_count));
                ioctl(fd4, TIMER_START);

                /* Do some work.
                 */
                memcpy(dest, src, buffer_size);

                /* Read back the count and determine how long it took to do
                   the work.
                 */
                ioctl(fd4, TIMER_STOP);
                read(fd4, &end_count, sizeof (end_count));
                printf("Copy %d took %dus\n", ii, start_count - end_count);
        }

        ioctl(fd3, TIMER_INTERRUPT_DISABLE);
        ioctl(fd3, TIMER_STOP);

        close(fd3);
        close(fd4);

        return 0;
}


// If you have not already done so, load the driver.
sh# modprobe vmitmrf
// Now let's run our code.
sh$ ./tmr_example
Copying 1048576 bytes
Copy 1 took 4719us
Copy 2 took 4208us
Copy 3 took 4209us
Copy 4 took 4139us
Copy 5 took 3812us

Using the Timer Driver

There are four countdown timer devices (/dev/timer[1-4]). Timers 1 and 2 are 16-bit counters and timers 3 and 4 are 32-bit counters. The initial count can be set by writing an integer value to the timer's device file. The current timer count can be read as an integer from the device's file. The timer automatically reloads the initial count when the timer reaches zero.

Warning: The current timer count is not updated unless the timer is running, so if you just wrote a count to the device while the timer was halted, do not expect to read back the same value.

Each timer's clock rate is selectable. The ioctl command TIMER_RATE_SET sets the clock rate. The clock rate value is specified in kilohertz. The following rate values are available:

  • 2000 Khz
  • 1000 Khz
  • 500 Khz
  • 250 Khz

The timers can be started and stopped with the ioctl commands TIMER_START and TIMER_STOP respectively.

Periodic interrupts can be enabled and disabled with the ioctl commands TIMER_INTERRUPT_ENABLE and TIMER_INTERRUPT_DISABLE respectively. An interrupt will be triggered each time the counter reaches 0. The counter is automatically reloaded when the timer expires. User code can wait for a periodic interrupt by using the select function call. To use select to wait for a timer interrupt, the file descriptor for the timer is added to the file descriptor set and that file descriptor set is passed in as the exception file descriptor set parameter to the select function call as is demonstrated in the above example.



Copyright 2006 GE Fanuc Embedded Systems, Inc. Questions, Comments, Corrections? Email support.embeddedsystems@gefanuc.com.