VMITMR-7305: GE Fanuc Timer Driver

Contents:

Abstract
Installation
Loading and Unloading the Module
Writing Applications Using the VMITMR-7305 Driver
Using the Timer Driver

Abstract

The vmitmr-7305 driver is a loadable Linux device driver module for GE Fanuc single board computers (SBCs) with a GE Fanuc I/O mapped FPGA timer device. SBCs currently supported by this driver include:

  • VMICPCI-7305
  • VMIPC4-7301
  • VMIOMAX-8451

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 vmitmr-7305 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 vmitmr-7305 driver, it must first be compiled (built) into executable code and installed. The next code listing illustrates how to compile and install the vmitmr-7305 driver.

Code listing 1: Compiling and Installing the VMITMR-7305 Driver

// From the vmitmr-7305 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/
vmitmr-7305.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

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 vmitmr-7305.

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

To unload the module, enter modprobe -r vmitmr-7305.

Writing Applications Using the VMITMR-7305 Driver

The vmitmr-7305 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 onboard timers.
// 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 fd1, fd3, count, rate, ii, start_count, end_count;
        char src[buffer_size], dest[buffer_size];
        fd_set fds;

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

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

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

        rate = 1000;
        count = 0xffff;
        ioctl(fd1, TIMER_RATE_SET, &rate);
        write(fd1, &count, sizeof (count));
        ioctl(fd1, TIMER_INTERRUPT_ENABLE);
        ioctl(fd1, TIMER_START);

        /* Set timer 3 for 1Mhz and start it running
         */
        rate = 1000;
        ioctl(fd3, TIMER_RATE_SET, &rate);

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

                /* Write an initial count and start the timer.
                 */
                write(fd3, &start_count, sizeof (start_count));
                ioctl(fd3, 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(fd3, TIMER_STOP);
                read(fd3, &end_count, sizeof (end_count));
                printf("Copy %d took %dus\n", ii, start_count - end_count);
        }

        ioctl(fd1, TIMER_INTERRUPT_DISABLE);
        ioctl(fd1, TIMER_STOP);

        close(fd1);
        close(fd3);

        return 0;
}


// If you have not already done so, load the driver.
sh# modprobe vmitmr-7305
// Now let's run our code. From the test directory execute,
sh$ ./tmr_example
Copying 1048576 bytes
Copy 1 took 30567us
Copy 2 took 12203us
Copy 3 took 12253us
Copy 4 took 12171us
Copy 5 took 12294us

Using the Timer Driver

There are three 16-bit countdown timer devices (/dev/timer[1-3]). 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.