VMITMR_82C54: GE Fanuc Timer Driver

Contents:

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

Abstract

The vmitmr_82c54 driver is a loadable Linux device driver module for GE Fanuc single board computers (SBCs) with a real-time clock device. SBCs currently supported by this driver include:

  • VMICPCI-7593
  • VMICPCI-7594
  • VMICPCI-7696
  • VMICPCI-7697
  • VMICPCI-7699
  • VMICPCI-7715
  • VMICPCI-7716
  • VMIVME-7591
  • VMIVME-7592
  • VMIVME-7695
  • VMIVME-7698
  • VMIVME-7740

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

Code listing 1: Compiling and Installing the VMITMR_82C54 Driver

// From the vmitmr_82c54 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_82c54.ko
// This header file contains the ioctl calls and others macros
sh$ ls /usr/include/linux/hwtimer.h
vmirtc.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_82c54.

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

To unload the module, enter modprobe -r vmitmr_82c54.

Writing Applications Using the VMITMR_82C54 Driver

The vmitmr_82c54 driver supports the following standard Linux system calls:

  • open
  • close
  • read
  • write
  • 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 rtc_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, ii, start_count, end_count;
        char src[buffer_size], dest[buffer_size];
        fd_set fds;

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

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

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

        start_count = 0xffff;   /* This is a 16-bit counter */
        write(fd1, &start_count, sizeof (start_count));
        ioctl(fd1, TIMER_INTERRUPT_ENABLE);
        ioctl(fd1, TIMER_START);
        write(fd3, &start_count, sizeof (start_count));

        /* Copy some data every time we get an interrupt for 5 iterations.
           Measure the time it took to complete the memcpy for each iteration.
           It is assumed that the timer is running at 1Mhz.
         */
        printf("Copying %d bytes\n", buffer_size);
        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_82c54
// Now let's run our code.
sh$ ./tmr_example
Copying 1048576 bytes
Copy 1 took 11981us
Copy 2 took 9925us
Copy 3 took 9976us
Copy 4 took 9948us
Copy 5 took 9975us

Using the Timer Driver

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

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.