Chapter 3. External Interrupts

Real-time processes often require the ability to react to an external event. External interrupts are a way for a real-time process to receive a real-world external signal.

An external interrupt is generated via a signal applied to the external interrupt socket on systems supporting such a hardware feature, such as the SGI PCIE-RT cards, which have a 1/8-inch stereo-style jack into which a 0-5V signal can be fed. An exterior piece of hardware can assert this line, causing the card to generate an interrupt.

This chapter discusses the following:

Abstraction Layer

Various external interrupt hardware might implement the external interrupt feature in very different ways. The external interrupt abstraction layer provides the ability to determine when an interrupt occurs, to count the number of interrupts, and to select the source of those interrupts without depending upon specifics of the device being used.

This section discusses the following:

sysfs Attribute Files

The external interrupt abstraction layer provides a character device and sysfs attribute files to control operation.

Assuming the usual /sys mount-point for sysfs, the attribute files are located in the following directory:

/sys/class/extint/extint#/                          

The extint# component of the path is determined by the extint driver itself. The # character is replaced by a number (possibly multidigit), one per external interrupt device, beginning at 0. For example, if there were three devices, there would be three directories:

/sys/class/extint/extint0/
/sys/class/extint/extint1/
/sys/class/extint/extint2/

The sysfs attribute files are as follows. For more information, see “External Interrupt Output for the PCIE-RT Card”.

File

Description

dev

Contains the major and minor number of the abstracted external interrupt device. If sysfs, hotplug, and udev are configured appropriately, udev will automatically create a /dev/extint # character special device file with this major and minor number. If you prefer, you may manually invoke mknod(1) to create the character special device file. Once created, this device file provides a counter that can be used by applications in a variety of ways. See “The /dev/extint# Device”.

mode

Contains the shape of the output signal for interrupt generation. For example, the PCIE-RT card can set the output to one of the following: low, high, pulse, oneshot, toggle, or delay.

modelist

Contains the list of available valid output modes, one per line. These strings are the legal valid values that can be written to the mode attribute.


Note: For the SGI PCIE-RT card, there are other values that may be read from the mode attribute file that do not appear in modelist; these represent invalid hardware states. Only the modes present from the modelist are valid settings to be written to the mode attribute.


period

Contains the repetition interval for periodic output signals (such as repeated strobes, automatic toggling). This period is specified in nanoseconds, and is written as a string.

provider

Contains an indication of which low-level hardware driver and device instance are attached to the external interrupt interface. This string is free-form and is determined by the low-level driver.

quantum

Contains the interval to which any writes of the period attribute will be rounded. Because external interrupt output hardware may not support nanosecond granularity for output periods, this attribute allows you to determine the supported granularity. The behavior of the interrupt output (when a value that is not a multiple of the quantum is written to the period attribute) is determined by the specific low-level external interrupt drive. However, generally the low-level driver should round to the nearest available quantum multiple. For example, suppose the quantum value is 7800. If a value of 75000 was written into the period attribute, this would represent 9.6 quantums. The actual period will be rounded to 10 quantums, or 78000 nanoseconds. The actual period will be returned upon subsequent reads from the period attribute.

source

Contains the hardware source of interrupts. For example, the SGI PCIE-RT card can trigger either from the external input or from the card's internal timer section, or both.

sourcelist

Contains the list of available interrupt sources, one per line. These strings are the legal values that can be written to the source attribute file.

The /dev/extint# Device

This section discusses the operations that an application can perform with the read-only external interrupt device file /dev/extint #:

Counting Interrupts

A process may use mmap(2) to memory-map a single memory page from the external interrupt device file into the process' address space. At the beginning of this page, a counter of an unsigned long type is maintained. This counter is incremented with each external interrupt received by the device.

Alternatively, the read(2) system call returns a string representation of the counter's current value.

Waiting for Interrupts

The poll(2) and select(2) system calls allow a process to wait for an interrupt to trigger:

  • poll() indicates whether an interrupt has occurred since the last open(2) or read() of the file

  • select() blocks until the next interrupt is received

Exclusively Accessing a Device

The flock(2) system call with the options LOCK_EX|LOCK_MAND ensures exclusive write access to the device attribute files (for example, /sys/class/extint/extint #/mode).


Note: You must define the _GNU_SOURCE macro before including the header files in order to use the LOCK_MAND flag on the call to flock(2).

When this lock is obtained, only a process that has access to the corresponding file descriptor will be able to write to the attribute files for that device. Any other process that attempts a write(2) system call on one of these attribute files will fail with errno set to EAGAIN.

The flock() system call will block until there are no other processes that have the device file open and until no other flock() is active on the device. However, if LOCK_NB is passed to flock(), the call will fail and errno will be set to EWOULDBLOCK.

While a lock is in place, any attempt to call open(2) on the device will block. However, if O_NONBLOCK is passed to open(), the call will fail and errno will be set to EWOULDBLOCK.

To release the lock, call flock() with the LOCK_UN argument. The lock will also be automatically dropped when the last user of the corresponding file descriptor closes the file, including via a process exit. The lock will persist if the file descriptor is inherited across fork(2) or exec(2) system calls.


Note: You must not pass the LOCK_MAND flag along with the LOCK_UN flag. The flock() system call behavior is unspecified in this case.

Example 3-1 illustrates a method of searching for an unused external interrupt device that can be used exclusively by that program.

Example 3-1. Searching for an Unused External Interrupt Device

#define _GNU_SOURCE

#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
int main(void) {
        char devfile[PATH_MAX];
        int i = 0;
        int fd;
        int found = 0;
        int status;

try_again:
        /* Search for free /dev/extint# device */
        while (i <= 255) {
                sprintf(devfile, "/dev/extint%d", i);
                i++;

                fd = open(devfile, O_RDONLY|O_NONBLOCK);
                if (fd >= 0) {
                        /* Found a unlocked device. */
                        found = 1;
                        break;
                }

                /* An error occurred.  Check why. */
                if (EWOULDBLOCK == errno) {
                        /* Found a locked device. */
                        printf("Tried %s, but it is locked.\n", devfile);
                }
                /* Some other type of error, just try next device.
                 * But don't complain about non-existent devices.
                 */
                if (ENOENT != errno)
                        printf("Unexpected error opening %s: %s\n",
                               devfile, strerror(errno));
        }

        if (!found) {
                printf("Could not find unlocked extint device to use.\n");
                return 1;
        }

        /* Try locking this device to gain exclusive access. */
        status = flock(fd, LOCK_EX|LOCK_MAND|LOCK_NB);
        if (status != 0) {
                if (EWOULDBLOCK == errno) {
                        /* The device was available, but another process
                         * has locked it between the time we opened it
                         * and made the flock() call.
                         */
                        printf("Opened %s, but someone else locked it.\n",
                               devfile);
                } else {
                        /* Some other error occurred. */
                        printf("Unexpected error locking %s: %s\n",
                               devfile, strerror(errno));
                }
                /* Try the next device. */
                found = 0;
                close(fd);
                goto try_again;
        }

        /* Successfully gained exclusive use of device */
        printf("Exclusive use of %s established.\n", devfile);

        /* Application code begins... */

        /* ... application code ends. */

        /* Unlock and close external interrupt device */
        flock(fd, LOCK_UN);
        close(fd);

        /* Successful run */
        return 0;
}


Low-Level Driver Interface

The external interrupt abstraction layer as implemented by the extint device driver is used by the SGI pcie-rt driver to present a uniform interface to external interrupt users. It is possible for third-party or end-user device drivers to interface to the extint driver as well, as described below.

The extint_properties and extint_device structures provide the low-level driver interface to the abstraction layer driver. The /usr/local/include/extint.h file defines the structures and function prototypes.

This section discusses the following:

Driver Registration

To register the low-level driver with the abstraction layer, use the following call:

struct extint_device*
extint_device_register(struct extint_properties *ep,
                       void *devdata);

The ep argument is a pointer to an extint_properties structure that specifies the particular low-level driver functions that the abstraction layer should call when reading/writing the attributes described in “sysfs Attribute Files”.

The devdata argument is an opaque pointer that is stored by the extint code. To retrieve or modify this value, use the following calls:

void* extint_get_devdata(const struct extint_device *ed);
void extint_set_devdata(struct extint_device *ed, void* devdata);

The low-level driver may use the devdata value in any manner desired, because the extint driver does not interpret its contents.

The return value is one of the following:

  • A pointer to a struct extint_device (which should be saved for later interrupt notification and driver deregistration).

  • A negative error value (in case of registration failure). The driver should be prepared to deal with such failures.

Implementation Functions

The struct extint_properties call table is as follows:

struct extint_properties {
        /* Owner module */
        struct module *owner;

        /* Get/set generation mode */
        ssize_t (*get_mode)(struct extint_device * ed, char *buf);
        ssize_t (*set_mode)(struct extint_device * ed, const char *buf,
                            size_t count);

        /* Get generation mode list */
        ssize_t (*get_modelist)(struct extint_device * ed, char *buf);

        /* Get/set generation period */
        unsigned long (*get_period)(struct extint_device * ed);
        ssize_t (*set_period)(struct extint_device * ed, unsigned long period);

        /* Get low-level provider name */
        ssize_t (*get_provider)(struct extint_device *ed, char *buf);

        /* Generation period quantum */
        unsigned long (*get_quantum)(struct extint_device * ed);

        /* Get/set ingest source */
        ssize_t (*get_source)(struct extint_device * ed, char *buf);
        ssize_t (*set_source)(struct extint_device * ed, const char *buf,
                              size_t count);

        /* Get ingest source list */
        ssize_t (*get_sourcelist)(struct extint_device * ed, char *buf);

        /* Arm/disarm timer */
        int64_t (*arm_timer)(struct extint_device * ed, int64_t ns, int when);
        void (*disarm_timer)(struct extint_device * ed);
};


Note: Additional fields not of interest to the low-level external interrupt driver may be present. You should include /usr/local/include/extint.h to acquire these structure definitions.

The owner value should be set to the module that contains the functions pointed to by the remaining structure members. The remaining functions implement low-level aspects of the abstraction layer attributes. They all take a pointer to the struct extint_device as was returned from the registration function. In all of these functions, you can retrieve the value passed as the devdata argument to the registration function by using the following call:

extint_get_devdata(ed);

You can update the value by using the following call:

extint_set_devdata(ed, newvalue);

Typically, this value is a pointer to driver-specific data for the individual device being operated upon. It may, for example, contain pointers to mapped PCI regions where control registers reside.

Field

Description

owner

Specifies the module that contains the functions pointed to by the remaining structure members.

get_mode

Writes the current mode attribute of the abstraction layer into the single-page-sized buffer passed as the second argument and returns the length of the written string.

set_mode

Reads the mode attribute of the abstraction layer as specified in the buffer (passed as the second argument and as sized by the third) and returns the number of characters consumed (or a negative error number in event of failure). It also causes the output mode to be set as requested.

get_modelist

Writes strings representing the available interrupt output generation modes into the single-page-sized buffer passed as the second argument, one mode per line. It returns the number of bytes written into this buffer. This implements the modelist attribute of the abstraction layer.

get_period

Returns an unsigned long that represents the current repetition period, in nanoseconds. This implements the period attribute of the abstraction layer.

set_period

Accepts an unsigned long as the new value for the repetition period, specified in nanoseconds, and returning either 0 or a negative error number indicating a failure. If the requested repetition period is not a value that can be exactly set into the underlying hardware, the driver is free to adjust the value as it sees fit, although typically it should round the value to the nearest available value. This implements the period attribute of the abstraction layer.

get_provider

Writes a human-readable string that identifies the low-level driver and a particular instance of a driven hardware device. For example, if the low-level driver provides its own additional device files for extra functionality not present in the abstraction layer, this routine might emit the name of the driver module and the names (or device numbers) of the low-level driver's own character special device files. This implements the provider attribute of the abstraction layer.

get_quantum

Returns an unsigned long that represents the granularity to which the interrupt output repetition period can be set, in nanoseconds. This implements the quantum attribute of the abstraction layer.

get_source

Writes the current interrupt input source into the single-page-sized buffer passed as the second argument and returns the length of the written string. This implements the source attribute of the abstraction layer.

set_source

Reads the source specified in the buffer (passed as the second argument and as sized by the third) and returns the number of characters consumed or a negative error number in event of failure. It also causes the input source to be selected as requested. This implements the source attribute of the abstraction layer.

get_sourcelist

Writes strings representing the available interrupt input sources into the single-page-sized buffer passed as the second argument, one source per line. It returns the number of bytes written into this buffer. This implements the sourcelist attribute of the abstraction layer.

arm_timer

Sets up the external interrupt device to generate an interrupt at a specified time. The time is specified in nanoseconds via the second argument. The third parameter may be set to the values EXTINT_TIMER_RELATIVE or EXTINT_TIMER_ABSOLUTE. The third parameter controls whether the time is relative to the moment the function is called or is absolute system time, (as returned by the getnstimeofday() system call). Interrupt notifications occur through the standard external interrupt callout mechanism described in “Interrupt Notification Interface”. This field may be set to NULL if the low-level driver does not support timer functionality.

disarm_timer

Cancels a pending interrupt, if any, scheduled to be delivered due to a prior call to the arm_timer() function. If the previously scheduled interrupt has already occurred, it is not necessary to call disarm_timer(), and calling disarm_timer() when no interrupt is pending should be harmless. This field may be set to NULL if the low-level driver does not support timer functionality.

When an External Interrupt Occurs

When an external interrupt signal triggers an interrupt that is handled by the low-level driver, the driver should make the following call:

void
extint_interrupt(struct extint_device *ed);

This allows the abstraction layer to perform any appropriate abstracted actions, such as update the interrupt count or trigger poll/ select actions. The sole argument is the struct extint_device that was returned from the registration call.

Driver Deregistration

When the driver desires to deregister a particular device previously registered with the abstraction layer, it should make the following call:

void
extint_device_unregister(struct extint_device *ed);

The sole argument is the struct extint_device that was returned from the registration call. There is no error return from this call, but if invalid data is passed to it, the likelihood of a kernel panic is very high.

Making Use of Unsupported Hardware Device Capabilities

If your hardware device supports capabilities that are not provided for in the abstraction layer, you can do one of the following:

  • Add a new attribute to the abstraction layer by modifying struct extint_properties to add appropriate interface routines and update any existing drivers as necessary.

  • Have the low-level driver create its own device class and corresponding attributes and/or character special devices. This method is preferred and is required if the capability is dependent on the hardware in a method that cannot be abstracted.

For example, the SGI PCIE-RT card has the ability to map the interrupt output control register directly into a user application in order to avoid the kernel overhead of reading/writing the abstracted attribute files. Using this capability means that the application must have intimate knowledge of the control register's format, something that cannot be abstracted away by the kernel and is very specific to this particular hardware implementation. This capability is provided by the pcie_rt driver, which supplies its own character special device along with a pcie_rt device class.

Interrupt Notification Interface

In addition to the user-visible aspects of the external interrupt abstraction layer, there is a kernel-only interface available for interrupt notification. This interface provides the ability for other kernel modules to register a callout to be invoked whenever an external interrupt is ingested for a particular device.

This section discusses the following:

Callout Mechanism

For systems (not just applications) that are critically interested in responding as quickly as possible to an externally triggered event, waiting for a poll/select operation, or even busy-waiting on the value of the interrupt counter to change, may have unexpected harmful effects (such as tying up a CPU spinning on a value) or may not provide appropriate response times.

A callout mechanism lets you write your own kernel module in order to gain minimal-latency notification of events and react accordingly. It also provides an extension capability that might be of interest in certain situations. For example, there could be an application that requires an interrupt counter page similar to the one maintained by the abstraction layer, but that starts counting at 0 when the device special file is opened. Or, there could be an application that requires a signal to be generated and delivered to the process when an interrupt is ingested. These examples are more esoteric than the simple counter page, and are best provided by a separate module rather than cluttering the main external interrupt abstraction code.

Callout Registration

To register a callout to be invoked upon interrupt ingest, allocate a struct extint_callout , fill it in, and pass it to the following call:

int
extint_callout_register(struct extint_device *ed,
                        struct extint_callout *ec);

The first argument is the struct extint_device corresponding to the particular abstracted external interrupt hardware device of interest. How this structure is found is up to the caller; however, the file_to_extint_device function will convert a struct file pointer to a struct extint_device pointer. This function will return -EINVAL if an inappropriate file descriptor is passed to it.

The second argument is one of the following structures:

struct extint_callout {
        struct module* owner;
        void (*function)(void *);
        void *data;
};


Note: Additional fields not of interest to the external interrupt user may be present. You should include /usr/local/include/extint.h to acquire these structure definitions.

The owner field should be set to the module containing the function and data pointed to by the remaining fields.

The function pointer is a callout function that is to be invoked whenever an interrupt is ingested by the abstraction layer for the device of interest. The data field is the only argument passed to it; it is used opaquely and is provided solely for use by the caller. That is, the abstraction layer will invoke the following upon each interrupt of the specified device:

ec->function(data);

You can register multiple callouts for the same abstracted external interrupt device. They will be invoked in no guaranteed order, but will be invoked one at a time.

The interrupt counter will be incremented before the callouts are invoked, but before any signal/poll notifications occur.

The module specified by the owner field in the callout structure, as well as the module corresponding to the low-level external interrupt device driver, will have their reference counts increased by one until the callout is deregistered.

Callout Deregistration

To remove a callout, call the following with the same arguments as provided during callout registration:

extern void
extint_callout_unregister(struct extint_device *ed,
                          struct extint_callout *ec);

You can remove both active and orphaned callouts in this manner with no distinction between the two.

The callout function must continue to be able to be invoked until the call to extint_callout_unregister completes.

Low-level Driver Template

You can use the pcie_rt.c file as a template for a low-level driver. The file is shipped as part of the extint source RPM.


Note: In addition to providing the abstraction interface, this low-level driver creates a character special device and a device class that are both specific to PCIE-RT.


Example: SGI PCIE-RT Real-Time Interrupt Card

This section describes the following for the SGI PCIE-RT real--time interrupt card:

Overview of the PCIE-RT Card

The PCIE-RT real-time interrupt card provides an interface to external circuitry. It can be used to ingest and generate a simple signal for the following uses:

  • On the output side, one of the jacks can provide a small selection of output modes that create a 0-5V electrical output

  • On the input side, one of the jacks will cause the PCIE-RT card to generate an interrupt on the transition edge of an electrical signal

The PCIE-RT card can also be used to generate interrupts within the host system itself without interfacing to external circuitry.

The pcie_rt driver registers itself with the extint abstracted external interrupt driver and lets it take care of the user-facing details.

External Interrupt Output for the PCIE-RT Card

The output section provides several modes of output. The mode is configurable by the abstraction layer device's mode attribute. The abstraction layer device's modelist attribute contains available modes. The modes are as follows:

Mode

Description

delay

Delays for a specified period with the output set to logic low, then sets the output to logic high for a duration of one half of the delay period. The output does not repeat.

high

Sets the output to logic high. The high state of the card's electrical output is normally a low voltage (0V).

low

Sets the output to logic low. The low state of the card's electrical output is normally a high voltage (+5V).

oneshot

Sets the output to logic high immediately, holds for a specified period, then returns to logic low. The output does not repeat.

pulse

Sets the output to logic high for half of a specified period, then logic low for the other half of the specified period, then repeats. The specified period is the reciprocal of the waveform frequency.

toggle

Alternates the output between logic low and logic high for a specified period. The specified period is the reciprocal of one half of the waveform frequency.

The period can be set to a range of values determined by the reference clock of the PCIE-RT hardware. For pulse and toggle modes, this period determines how often the pulse or toggle occurs. The period can be set only to a multiple of this length (rounding will occur automatically in the driver). The period should be configurable by the abstraction-layer device's period attribute, and the tick length can be found from the abstraction-layers device's quantum attribute. For certain modes, there may be minimum or maximum period values enforced by the driver so that the PCIE-RT logic or output sections function correctly.

One device file is provided, which can be memory mapped. This file provides direct access to the PCIE-RT hardware registers that control output and input. Directly manipulation of the register, both for reading and writing, may be performed in order to avoid the kernel overhead that would be necessary if using the abstracted interfaces.

Assuming the typical sysfs mount point, the device number files for these devices can be found at:

/sys/class/pcie_rt/pcie_rt#/dev

This capability is not abstracted into the external interrupt abstraction layer because it is critical for an application to know that this is PCIE-RT device in order to determine the format of the mapped registers. Table 3-1 shows the register format. The value in the Attribute column of the table describes the register access semantics of the corresponding field, as follows:

RO

Read-only

RW

Read-write

RW-V

Read-write, volatile value

RW1C

Read-write; write 1 to clear

RW1C-V

Read-write, volatile value; write 1 to clear


Note: There are the following considerations:

  • Registers should always be read and written as 32-bit words in order to avoid byte order difference concerns.

  • Any fields or register offsets not described in the table should be treated as reserved. Such register fields should always be written with the same value read from them, and software should not depend on their value.

  • The list of registers and fields is current and complete with all versions of the PCIE-RT card released as of March 2, 2015.



Table 3-1. Register Format for the SGI PCIE-RT Card

Offset (bytes)

Name

Bits

Field

Attribute

Description

0x0

VERSION

31:24

LOGIC_MAJOR

RO

FPGA logic major version number.

 

 

23:16

LOGIC_MINOR

RO

FPGA logic minor version number.

 

 

15:8

BOARD_ID

RO

Model number (that is, major version) of PCIE circuit board.

 

 

7:0

BOARD_VERSION

RO

Version number of PCIE circuit board.

0x4

REFCLK_FREQ

31:0

FREQUENCY

RO

Output logic reference clock frequency

0x8

INGEST_EN

16

EXTERNAL

RW

Enable interrupts from external pin

 

 

0

TIMER

RW

Enable interrupts from timer logic

0xC

INGEST_STATUS

24

EXTERNAL_OVR

RW1C-V

A second interrupt was signaled at the external pin before a previous interrupt was acknowledged

 

16

EXTERNAL

RW1C-V

Interrupt signaled at the external pin, write 1 to clear and acknowledge

 

8

TIMER_OVR

RW1C-V

A second interrupt was signaled from internal timer logic before a previous interrupt was acknowledged

 

0

TIMER

RW1C-V

Interrupt signaled from internal timer logic, write 1 to clear and acknowledge

0x8

INGEST_EN

16

EXTERNAL

RW

Enable interrupts from external pin

 

0

TIMER

RW

Enable interrupts from timer logic

0xC

INGEST_STATUS

24

EXTERNAL_OVR

RW1C-V

A second interrupt was signaled at the external pin before a previous interrupt was acknowledged

 

16

EXTERNAL

RW1C-V

Interrupt signaled at the external pin, write 1 to clear and acknowledge

 

8

TIMER_OVR

RW1C-V

A second interrupt was signaled from internal timer logic before a previous interrupt was acknowledged

 

0

TIMER

RW1C-V

Interrupt signaled from internal timer logic, write 1 to clear and acknowledge

0x10

INGEST_RAW

16

EXTERNAL

RO

Current logic state being driven at external pin without respect to enables

 

0

TIMER

RO

Current logic state being driven from internal timer logic without respect to enables

0x14

INGEST_CTRL

2

TIMER_EDGE

RW

Select edge of timer logic signal to generate interrupt:

  • 0 = Rising edge

  • 1 = Falling edge

 

1

EXTERNAL_INVERT

RW

Logically invert the external source signal input

 

0

EXTERNAL_EDGE

RW

Select level or edge triggered interrupts from external source:

  • 0 = Level-triggered

  • 1 = Edge-triggered

0x18

TIMER_CTRL

16

OUT_INVERT

RW

Invert output signal at external pin

 

8

OUT_EN

RW

Enable output of timer logic waveform at external pin

 

1:0

MODE

RW

Timer logic output waveform behavior:

  • 0 = LOW: Output is logic low. The counters do not reload.

  • 1 = HIGH: Output is logic high. The counters do not reload.

  • 2 = PULSE: TIMER_PERIOD_CTR and TIMER_WIDTH_CTR count down. When TIMER_WIDTH_CTR is nonzero, the output is logic high, otherwise it is logic low. The counters reload when the period counter is 0.

  • 3 = ONESHOT: TIMER_WIDTH_CTR counts down. When TIMER_WIDTH_CTR is nonzero, the output is logic high, otherwise it is logic low. The counters do not reload.

0x1C

TIMER_PERIOD

31:0

COUNT

RW

Value reloaded into TIMER_PERIOD_CTR when TIMER_PERIOD_COUNTER reaches 0 and TIMER_CTRL.MODE=2 (PULSE).

0x20

TIMER_WIDTH

31:0

COUNT

RW

Value reloaded into TIMER_WIDTH_CTR when TIMER_PERIOD_COUNTER reaches 0 and TIMER_CTRL.MODE=2 (PULSE)

0x24

TIMER_PERIOD_CTR

31:0

COUNT

RW-V

Current period (that is, overall waveform period) countdown value

0x28

TIMER_WIDTH_NEXT

31:0

COUNT

RW-V

Current width (that is, logic high period) countdown value

0x2C

TIMER_NEXT

9

WIDTH_CTR_SELECT

RW

Specifies value loaded to TIMER_WIDTH_CTR:

  • 0 = Load TIMER_WIDTH_NEXT

  • 1 = Load TIMER_WIDTH_CTR_NEXT

 

8

PERIOD_CTR_SELECT

RW

Specifies value loaded to TIMER_PERIOD_CTR:

  • 0 = Load TIMER_PERIOD_NEXT

  • 1 = Load TIMER_PERIOD_CTR_NEXT

 

1:0

LOAD

RW-V

Trigger load of TIMER_CTRL, TIMER_PERIOD, and TIMER_WIDTH from TIMER_CTRL_NEXT, TIMER_PERIOD_NEXT (or TIMER_PERIOD_CTR_NEXT), and TIMER_WIDTH_NEXT (or TIMER_WIDTH_CTR_NEXT ) in the following manner:

  • 0 = Do nothing (no values loaded)

  • 1 = Load values immediately

  • 2 = Load values when TIMER_PERIOD_CTR reaches 0

  • 3 = Load values when TIMER_WIDTH_CTR reaches 0

0x30

TIMER_CTRL_NEXT

31:0

NEXT

RW

Value to be loaded to TIMER_CTRL according to TIMER_NEXT settings

0x34

TIMER_PERIOD_NEXT

31:0

NEXT

RW

Value to be loaded to TIMER_PERIOD and optionally TIMER_PERIOD_CTR according to TIMER_NEXT settings

0x38

TIMER_WIDTH_NEXT

31:0

NEXT

RW

Value to be loaded to TIMER_WIDTH and optionally TIMER_WIDTH_CTR according to TIMER_NEXT settings

0x3C

TIMER_PERIOD_CTR_NEXT

31:0

NEXT

RW

Value to be loaded to TIMER_PERIOD_CTR according to TIMER_NEXT settings

0x40

TIMER_WIDTH_CTR_NEXT

31:0

NEXT

RW

Value to be loaded to TIMER_WIDTH_CTR according to TIMER_NEXT settings.


External Interrupt Ingest for the PCIE-RT Card

The ingest section provides control over the source of interrupt signals. The external source is a circuit connected to the external jack provided on PCIE-RT cards. The timer source is the output of the external interrupt output timer logic, with the loopback source being the same as the timer, but provided for compatibility with existing software written for IOC4. Options of both and none are also available. The source is configurable by the abstraction layer's source attribute. You can find available sources in the abstraction layer device's sourcelist attribute.

For example, to set up a 100-ms (10-Hz) repeating timer, you would issue the following commands:

[root@linux root]# echo timer > /sys/class/extint/extint0/source 
[root@linux root]# echo 100000000 > /sys/class/extint/extint0/period
[root@linux root]# echo pulse > /sys/class/extint/extint0/mode

Physical Interfaces for the PCIE-RT Card

Use a two-conductor shielded cable to connect external interrupt output and input, with the two cable conductors wired to the +5V and interrupt conductors and the sleeves connected to the cable shield at both ends to maintain EMI integrity.

The PCIE-RT card implementation uses female 3.5mm audio jacks. The wiring for the jack is as follows:

  • Tip: +5V input

  • Ring: Interrupt input (optoisolated)

  • Sleeve: Chassis ground/cable shield

The input signal passes through an optoisolator that has a damping effect. The input signal must be of sufficient duration to drive the output of the optoisolator low in order for the interrupt to be recognized by the receiving system. The exact timing constraints may depend on cable quality and drive strength, and experimentation may be necessary to determine a safe value.

Figure 3-1 shows the internal driver circuit for the output connector and the internal receiver circuit for the input connector.

Figure 3-1. Output and Input Connectors for Interface Circuits of PCIE-RT Cards

Output and Input Connectors for Interface Circuits
of PCIE-RT Cards