Archived: Triggering with NI-VXI

NI does not actively maintain this document.

This content provides support for older products and technology, so you may notice outdated links or obsolete information about operating systems or other relevant products.

Overview

This document discusses the VXI triggering and triggering protocols defined by the VXIbus System Specification, Revisions 1.3 and 1.4. This document is written for two groups of users. Those interested in basic triggering will find information sufficient for most applications in the material through the Program Control section, excluding the discussion of the SEMI-SYNC trigger protocol. For those users who are experienced with triggers and have a more complicated application in terms of triggering, the Advanced TIC Trigger Functions section through the end of the document contains information that reveals the true power of the Trigger Interface Chip (TIC). For your convenience, refer to the following table of contents.

Through the combination of the National Instruments VXIbus Application Programming Interface (API), known as NI-VXI, and the TIC chip, National Instruments provides a fully functional and flexible solution to VXI device triggering. This document examines from a user's perspective the trigger interface section of the NI-VXI API to show how you can implement triggering and trigger handling. Other VXI controllers may have limited trigger capability, but with the TIC, National Instruments has developed a way to perform all VXIbus defined triggering as well as signal routing, counting, and timing. This document discusses the TIC in the context of the NI-VXI API and gives examples to demonstrate the chip's capabilities.

Contents

History of Triggering

For many years, engineers and computer system integrators have taken advantage of readily available off-the-shelf boards and the modular chassis of the VMEbus to rapidly construct high-performance computer systems. Designed as a general computer bus, the VMEbus has been used in applications as diverse as parallel processing research to industrial process control. The VMEbus specification defines basic data transfers, multi-master bus arbitration, and a multiple device interrupt scheme which are common to any applications requiring intelligent communication or control. However, for many other applications needing precise synchronization, further definition is necessary. Specifically, for instrumentation control, the VMEbus lacks several features such as the ability to precisely time and synchronize measurement and stimulus devices. The VMEbus introduced a faster instrument platform to test systems, but did nothing to address the issues regarding triggering, timing, and synchronization of instruments. Even traditional rack-and-stack, IEEE 488-based systems required a certain amount of creativity from engineers to build a system that met system timing requirements. After finding the right cable, calculating cable propagation delays, and writing the appropriate software, many engineers were frustrated that simple triggering required so much effort.

The VXIbus (VME eXtensions for Instrumentation) Consortium created a computer bus architecture that not only captured the speed and flexibility of the VMEbus, but also contained enhancements for instrumentation and instrumentation control. One of these enhancements was the addition of dedicated backplane lines for timing and triggering. These lines can be used not only in the familiar application of triggering the beginning or end of a data acquisition sequence, but also to sequence a state machine in automatic testing or as a bus for digital communication.

The VXIbus specification defines triggering protocols for simple triggers as well as trigger protocols that support acknowledgment from VXI devices. Devices implementing a VXIbus-defined protocol automatically possess an effective timing mechanism for synchronizing events. Consider the case of a VXI controller running a test program to take a measurement from a Digital Multimeter (DMM). The controller running a test program uses a backplane trigger to tell the DMM to take a measurement. The DMM receives the trigger and then takes the measurement. When the DMM is finished, it can tell the controller that it is finished by acknowledging the trigger. When the controller detects the acknowledgment, then it can read the measurement from the DMM and the sequence is complete. This is a simple case, but the implications are important. In a system that implements many instruments, controlling the system through backplane triggers improves system performance while requiring little software development.

VXI Defined Trigger Protocols


The VXIbus specification defines eight TTL trigger lines (TTLTRG0* through TTLTRG7*) and six ECL trigger lines (ECLTRG0 and ECLTRG1 on the P2 connector, for B-, C-, and D-sized cards, and ECLTRG2 through ECLTRG5 on P3, for D-sized cards). Although the specification defines the electrical and mechanical specifications, the VXIbus Consortium did not dictate the use or allocation of these lines. Indeed, because the Resource Manager ignores the trigger lines, the system integrator is free to determine their allocation. However, so that devices from multiple vendors can work together, the consortium did define some protocols that could be used. The following sections discuss the TTL protocols as defined in the VXIbus specification,
Revision 1.4.

The SEMI-SYNC protocol was removed in Revision 1.4 due to a problem in the definition of the protocol with regard to multiple acceptors. Although this protocol has been removed, it is likely to be in later revisions of the specification in a modified form. The SEMI-SYNC protocol is presented here because it is still a useful protocol and it is available in NI-VXI. For more information on this protocol, refer to the Semi-Synchronous (SEMI-SYNC) Trigger Protocol and Understanding the SEMI-SYNC Trigger Protocol sections later in this document.

Note: Because the ECL differ from TTL only in the electrical levels used in their logic and timing, the essence of the protocols for ECL trigger lines are the same. Therefore, the following definitions are all based on TTL logic. Please refer to the VXIbus specification for more information.

TTLTRG* Synchronous (SYNC) Trigger Protocol
The SYNC protocol is used as a single-line, single-pulse trigger that does not require any acknowledgment from the accepting devices. This is the simplest protocol and is what most people would think of when working with triggering. The trigger line is in a logic high state until such time that the application requires all devices listening to the trigger line to react. This could be as simple as telling a DMM to take a reading, or as complex as the start signal to a data acquisition sequence. Figure 1 shows the timing specifications for the SYNC protocol as given in the VXIbus specification.


Figure 1. The SYNC Trigger Protocol

TTLTRG* Asynchronous (ASYNC) Trigger Protocol
The ASYNC protocol is a two-wire, single-acceptor protocol where the sourcing device sends a SYNC pulse down the source line, and the acceptor returns a SYNC pulse down the acceptor line. This protocol accommodates cases in which the sourcing device must synchronize itself with the acceptor device and so must wait until it receives an acknowledgment.

For example, a DMM can take up to a second to make a measurement. When the controller sends the trigger to the DMM, it would normally need to either poll the device to determine if it has completed the acquisition, or have the device generate an interrupt when it is ready. The ASYNC protocol simplifies the process by having the DMM trigger the master when the data is ready by sending the acknowledge pulse. Although this seems the same as an interrupt, the amount of activity on the bus is less because no interrupt acknowledge cycle is required1. See Figure 2 for the timing specifications of the ASYNC protocol.


Figure 2. The ASYNC Protocol

Notice that the only valid pairs of TTL lines for ASYNC are 0 and 1, 2 and 3, 4 and 5, and 6 and 7.

Start/Stop (STST) Trigger Protocol
The STST protocol provides broadcasting for start and stop messages to devices. Exactly how the device interprets the Start and Stop message depends on its design. For example, Start could tell a device to begin its data acquisition sequence and Stop could pause the sequence until the next Start trigger. Another example of the use of STST is a device that continuously acquires data. The sourcing device can assert the trigger line for a precise amount of time, during which time the device listening to the trigger line would acquire and average its data.

The STST protocol also allows a more precise timing on the trigger pulses. As you can see from Figure 3, these protocols use the 10 MHz CLK10 signal on the backplane to synchronize the trigger pulse. The use of the CLK10 signal gives the devices set-up time before they are required to trigger. In addition, the VXIbus specification defines that only the Slot 0 device can assert the STST protocol. Because the signal propagation delay between adjacent slots is approximately 2 ns, if each device knows the trigger signal is coming from Slot 0, and it knows its own slot, then it can use the CLK10 signal and the known propagation delays to achieve more precise triggering by reducing the timing skew from tens of nanoseconds to less than 10 ns. For example, if devices A and B are to take readings at the same time, and device A is in slot 2 and device B is in slot 12, then device A knows that there is a 20 ns delay between the time it sees the CLK10 edge and the time device B sees the clock edge. By internally delaying the trigger 20 ns, device A can trigger at very close to the same time that device B triggers off the original clock edge. For this mechanism to work, the devices must support this ability to internally delay the trigger by a few nanoseconds. See Figure 3 for the timing specifications of the STST protocol.


Figure 3. The STST Protocol

Semi-Synchronous (SEMI-SYNC) Trigger Protocol
The SEMI-SYNC protocol has been removed from Revision 1.4 of the VXIbus specification due to the discovery that the protocol has a wired-OR glitch problem. The SEMI-SYNC protocol takes advantage of the fact that the VXI trigger lines are open collector, which is also known as wired-OR. The intention of the SEMI-SYNC protocol is to allow a single source with multiple acceptors to communicate on a single line. However, wired-OR lines have a problem known as a wired-OR glitch which can occur when devices stop driving the line. For example, if device A drives the line low it must sink approximately 30 mA of current due to the electronics of the open collector circuitry. When device B drives the same line low, it will not have to sink as much current because device A is sinking most of it. However, if device A stops driving the line, the 30 mA current must be taken on by device B. Due to electrical restrictions, device B may not be able to sink all of the current fast enough to prevent the line from rising briefly, resulting in a glitch. If the glitch occurs during the SEMI-SYNC protocol, the sourcing device may mistakenly view the glitch as a signal that all the acknowledging devices have completed the protocol.

Even though there is no SEMI-SYNC protocol in the current revision of the VXIbus specification, it is still possible to use the SEMI-SYNC protocol with NI-VXI because the protocol works properly between a single source and a single acceptor device.

The sourcing device asserts the trigger line for 50 ns minimum (See Figure 4). Within 40 ns from seeing the assertion, all devices participating in the protocol also begin asserting the trigger. As the devices complete their respective tasks, they stop asserting the trigger line. Thus, when the last device has finished, the trigger line becomes unasserted. The original sourcing device can then detect this unasserted state, freeing it to read data, program for the next sequence, and so on. For example, a powerful use for this protocol is having multiple embedded computers synchronize with each other while performing parallel processing.


Figure 4. The SEMI-SYNC Protocol

NI-VXI Solutions to VXIbus Triggering

National Instruments has taken two specific actions to provide VXIbus trigger solutions. The first was to develop the triggering API in the NI-VXI driver (as well as the local command set for the GPIB-VXI).

The second action was to create the Trigger Interface Chip, or TIC ASIC. This chip has the ability to work with all the VXI-defined standard trigger protocols. The TIC also contains general-purpose counters and a cross-matrix switch for complex routing of trigger and clock signals. In addition, the TIC has 10 general-purpose input/output (GPIO) lines that can bring signals other than triggers into the TIC and can send trigger or counter signals out of the chip. On the National Instruments controllers, some of the GPIO lines already have been assigned to the external CLK10, the Front In, and Front Out connectors. The remaining GPIO lines are available for other uses.

The TIC chip comes standard on the GPIB-VXI and on the embedded computer line. This section looks at the features the TIC chip provides by examining the different NI-VXI functions for triggering, as well some examples illustrating the different uses of the API. For more information on the TIC chip, please see Appendix A.

Basic Trigger Functions
For a simple set of trigger functions, consider the case of generating triggers on the VXI backplane. Notice that systems without the TIC chip have triggering capabilities to the extent described here and in the following section, Program Control.

The function SrcTrig() lets you source a trigger using any of the VXI-defined protocols. It can assert the protocol on any of the TTL lines and ECL0-12. On a system without the TIC chip, you can source or monitor a single trigger line at a time. With the TIC, it is possible to source and monitor multiple lines simultaneously. If the platform has the TIC chip, you can also source the GPIO lines.

Note: The GPIO lines cannot source or acknowledge ASYNC nor SEMI-SYNC because they do not have the edge detection or interrupt circuitry necessary to operate these protocols.

You can also use SrcTrig() on the counter and timers in the TIC chip as described later in the TIC Counter Functions section. Also, because some of the trigger protocols are actually asynchronous handshaking, you can specify a timeout so that the function will wait for the acknowledge (see the discussions of the ASYNC and SEMI-SYNC protocols earlier in this document).

The following code is a simple example of sourcing a SYNC pulse.

Example 1 Sourcing the SYNC Trigger Protocol
/* Generate a SYNC pulse on TTL line 0 */
controller = -1;/* Local controller */
line = 0;           /* TTL0 */
prot = 4;           /* SYNC */
timeout = 0L;       /* No timeout */
ret = SrcTrig (controller, line, prot, timeout);

Program Control
A common requirement is to have the controller source the trigger protocols. However, there are cases where another device will source the trigger and it is up to the controller to respond. NI-VXI supports both cases easily. In addition, NI-VXI gives devices the ability to act as either the sourcing device or the acceptor device in all defined protocols.

If the controller is going to source a protocol that requires acknowledgment (ASYNC and SEMI-SYNC), you can program the SrcTrig() function not to return until the acknowledgment is received. The function also contains a timeout parameter to prevent the system from hanging if the acknowledge is never sent. In addition, if you wish to perform other tasks while waiting for the trigger acknowledge, SrcTrig() can return immediately so that the program can continue execution. The program can then respond to the acknowledge when it occurs through either the WaitForTrig() function or interrupts3. The following example initiates the ASYNC protocol with SrcTrig() and performs other tasks while waiting for the acceptor device to acknowledge.

Example 2 Sourcing ASYNC and Performing Other Tasks While Waiting for Acknowledge
/* Enable the Controller to detect the interrupts */
controller = -1;/* Local controller */
line = 2;           /* TTL2 */
prot = 6;           /* ASYNC - Don’t wait for acknowledge */
ret = EnableTrigSense(controller, line, prot);

/* Start the protocol but don’t wait for the acknowledge */
timeout = 0L;       /* No timeout */
ret = SrcTrig (controller, line, prot, timeout);

/* WaitForTrig() will return -6 to indicate a timeout */
/* has occurred.  Until it returns 0 indicating it   */
/* received the acknowledge, we can execute this loop */
while (WaitForTrig (controller, line, timeout)) {
     /**/
     /* Do whatever you need */
     /**/
}

There are also techniques you can use to have the controller respond to triggers sourced by another device. The first and simplest technique is to call EnableTrigSense() to tell the controller to watch for a protocol on a trigger line, and then issue WaitForTrig(), which causes the program to wait for the trigger source from the other device. At this point, the program can continue and the controller can respond to the trigger as required. Of course, your program does not have to remain idle while waiting for the trigger, because the WaitForTrig() is able to poll for trigger events. For example, the following code shows how to wait for the ASYNC protocol and let the controller perform other duties while waiting for the trigger.

Example 3 Using ASYNC in a Background Operation
/* Set CPU to watch for interrupts */
controller = -1;    /* Local controller */
line = 2;                /* TTL2 */
prot = 6;                /* ASYNC */
ret = EnableTrigSense (controller, line, prot);

/* WaitForTrig() will return -6 to indicate a timeout */
/* has occurred.  Until it returns 0 indicating it   */
/* received the trigger, we can execute this loop */
timeout = 0L;            /* No timeout */
while (WaitForTrig (controller, line, timeout)) {
     /**/
     /* Do whatever you need */
     /**/
}

The default interrupt handler acknowledges the ASYNC protocol for you when it detects the start of the protocol, so there is no need to call  AcknowledgeTrig(). If you do not want to acknowledge the trigger until after some action has been taken by your program, then you need to install your own interrupt handler.

If you are going to install your own interrupt handler, you still use EnableTrigSense() to arm the controller to detect trigger protocols. However, before calling this function, you use GetTrigHandler() and SetTrigHandler() to install your own interrupt service routine (ISR)4.

The first step is to obtain the handle for the current ISR by calling GetTrigHandler() 5 . Once you have the current ISR you install your own handler by calling SetTrigHandler(). As you can see from the Example 4, installing an ISR is not difficult. NI-VXI handles all the necessary steps for installing, invoking, and removing the ISR. However, the ISR you install still must follow the rules of ISRs for your system such as length of time to execute and the use of reentrant code only. See the documentation on programming supplied by the vendor of your operating system for more information.

Example 4 Installing Interrupt Handlers with NI-VXI
int global_var=0;
/* This is the syntax for the Trigger ISR.  Notice NIVXI_HQUAL */ /* and NIVXI_HSPEC must surround the ISR function name. */
void NIVXI_HQUAL (*oldhandle) NIVXI_HSPEC (int16, uint16,
                                   uint16);
void NIVXI_HQUAL myISR NIVXI_HSPEC (int16 controller, uint16
                              line, uint16 type)
{
    global_var++;        /* Perform some action */
}

run_interrupts() {

   /* Disable interrupts:  An interrupt being handled while */
   /* changing ISRs can crash the system */
   controller = -1;
   ret = DisableTrigSense (controller, 3);

   /* Obtain old ISR pointer for TTL3 */
   oldhandle = GetTrigHandler (1<<3);

   /* Install new ISR */
   ret = SetTrigHandler (1<<3, myISR);

   /* Enable interrupts */
   prot = 4;             /* SYNC */
   ret = EnableTrigSense (controller, 3, prot);
   ..
   .
   /* Disable interrupts */
   ret = DisableTrigSense (controller, 3);

   /* Reinstall old ISR */
   ret = SetTrigHandler (1<<3, oldhandle);

} /* END */

Notice that Example 4 can also be applied to the case where the controller sources a trigger protocol that has an acknowledgment (ASYNC or SEMI-SYNC) by issuing SrcTrig() after the call to EnableTrigSense().

Advanced TIC Trigger Functions
The following functions are used to configure advanced features of the TIC chip.
  • MapTrigToTrig()
  • UnMapTrigToTrig()
  • TrigAssertConfig()
  • TrigExtConfig()

Appendix A goes into much greater detail on the different modules that make up the TIC chip. This section uses a simplified view of the chip to help you gain an understanding of the NI-VXI functions without worrying about the details of the TIC chip. However, it is recommended that you understand the operation of the TIC in more detail if you plan to use the advanced features of the TIC extensively.

Figure 5, the TIC chip block diagram, shows how the external trigger and external GPIO lines can map to one another. Notice that GPINx and TRGINx are internal signals to the TIC. For now, consider these lines as pathways for connecting the external lines to one another. The functions listed previously are used to program the different modules that make up the TIC chip. How each of these modules is configured is described below. Notice that the terms internal and external are from the point of view of the TIC chip, not the controller.



The Crosspoint Switch block is simply a point-to-point switch. It connects each GPIO module to each Trigger module electrically, as well as connecting the counter and timer signals to these modules. When mapping external trigger lines, the function MapTrigToTrig() maps an external trigger line to and from an external GPIO line. It can also map the counter output signals to these external lines. Example 5 shows how to connect TTL0 to GPIO1 (which is connected to Front Panel Out), and GPIO0 (which is connected to Front Panel In) to TTL2.

Example 5 Mapping a Trigger Line to a GPIO Line
controller = -1;    /* Local controller */
mode = 0;                /* Sync with CLK10 */
SrcTrigger = 0;          /* TTL0 */
destTrig = 41;           /* GPIO1 = Front Out */
ret = MapTrigToTrig (controller, SrcTrigger, destTrig, mode);

SrcTrigger = 40;    /* GPIO0 = Front In */
destTrig = 2;            /* TTL2 */
ret = MapTrigToTrig (controller, SrcTrigger, destTrig, mode);

Keep in mind that you cannot map one external trigger line directly to another. As the diagrams of the TIC chip indicate, the crosspoint switch can send the external trigger line to the external GPIO line and vice versa. Therefore, if you want to connect two external trigger lines together, you must use a GPIO module as a wrapback, or short, between the two trigger lines. Example 6 shows how to create the electrical connection between TTL0 and TTL1 by shorting the GPIO module connected to the external GPIO9.

To use a GPIO module as a short for two external trigger lines, use the TrigExtConfig() function. It is easiest to think of this function as controlling the GPIO modules inside the TIC chip rather than the GPIO lines. For now consider each GPIO module—there is one module per external GPIO line—as a railroad junction that brings the external GPIO line into the TIC chip (See Figure 6). This railroad junction can do one of three things:
  • Propagate the signals out the external GPIO line.
  • Bring signals on the external GPIO lines into the TIC chip.
  • Disconnect the external GPIO lines from the chip electronically and short the input and output of the GPIO module together.


Figure 6. Simplified GPIO Module in the TIC Chip

This last feature makes it possible for you to physically connect trigger lines so that there is no software overhead involved in sending a trigger event from one trigger line to the other. The function uses a mode parameter to control the GPIO modules as shown in Table 1.
Table 1. TrigExtConfig() Mode Parameter Values
Bit Configuration Modes
0 1: Feed back any line mapped as input into
the crosspoint switch.
0: Drive input to external (GPIO) pin.
1 1: Assert input (regardless of feedback).
0: Leave input unconfigured.
2 1: If assertion selected, assert low.
0: If assertion selected, assert high.
3 1: Invert external input (not feedback).
0: Pass external input unchanged.

Therefore, bit 0 programs the TIC to either short the GPIO module (when bit 0=1) or connect the GPIO module input to the external GPIO line (when bit 0=0). Bit 1 lets you determine whether the GPIO module input is driven by software (when bit 1=1) or by the state of the GPIO module input. Bit 2 is relevant when you assert the line through software (that is, only when bit 1=1) and you use bit 3 when you want the module to bring the signal into the chip from the external GPIO line. The following code uses TrigExtConfig() to map trigger lines to trigger lines.

Example 6 Mapping a Trigger Line to a Trigger Line
/* This section will allow GPIO9 to be used as a short  */
/* circuit between TTL0 and TTL1 by configuring as a   */
/* feedback circuit (that is, disconnecting external lines) */
controller = -1;    /* Local controller */
extline = 49;            /* GPIO9 */
mode = 1;                /* Feedback, leave unconfigured */
ret = TrigExtConfig (controller, extline, mode);

/* Now connect TTL0 to GPIO9 and GPIO9 to TTL1 */
mode = 0;                /* Sync w/ CLK10 */
SrcTrigger = 0;          /* TTL0 */
destTrig = 49;           /* GPIO9 */
ret = MapTrigToTrig (controller, SrcTrigger, destTrig, mode);

SrcTrigger = 49;    /* GPIO9 */
destTrig = 1;            /* TTL1 */
ret = MapTrigToTrig (controller, SrcTrigger, destTrig, mode);

In addition to the GPIO module, the TIC chip has a Trigger module for each external trigger line that can be configured through  TrigAssertConfig(). The external trigger line is connected to the Trigger module and can either drive the Trigger module output or itself be driven by the Trigger module input. However, the internal routing capabilities of the Trigger module differ substantially from the GPIO module.

The Trigger module provides the following capabilities.
  • Synchronization with CLK10
  • Stretching the incoming pulses on the external trigger lines to a minimum length (pulse-stretching)
  • Edge detection and interrupt generation capabilities for monitoring external trigger lines
  • Participation in the hardware acknowledge of the SEMI-SYNC protocol

The pulse stretch feature means that the pulse of an external trigger line can be stretched in time before being mapped to another line. This feature can be very important when mapping a trigger line out of the chassis onto a long cable, which would require more settling time than the original pulse could provide, or sending the signal to another device that may not be able to respond to the small assertion times of the VXIbus trigger protocols. The  TrigAssertConfig() function handles the configuration of the pulse-stretch feature, as well as the other features of this module. This function uses a mode parameter similar to the TrigExtConfig() function. The hardware acknowledge feature for SEMI-SYNC is described in the Understanding the SEMI-SYNC Trigger protocol section later in this document. In addition, refer to Appendix A for a more in-depth description of the Trigger module.

TIC Counter Functions
Inside the TIC chip are three counters: a 16-bit counter and two 5-bit timers. Like the GPIO and Trigger modules discussed above, the counter and scalar modules are more thoroughly described in Appendix A. Please refer to the appendix for more information.

The 16-bit counter can be driven from the CLK10 signal, the EXTCLK signal, or any of the trigger lines on the P2 connector. The counter has two outputs: a 100 ns pulse on each clock edge (TCNTR), and a terminal count assertion (GCNTR). Both of these outputs are available to be mapped inside the crosspoint switch, with TCNTR connected to the Trigger module and GCNTR connected to the GPIO module.

When programming this counter, there are three possible modes that can be selected through TrigCntrConfig(): initialize, reload, and disable. The first call to the counter must be with the initialization mode. Once the counter has been initialized, a call to either EnableTrigSense() or SrcTrig() starts the counter. For example, the following code programs the counter to count for 100 ms (1000 clock pulses from CLK10).

Example 7 Using the 16-Bit Counter to Count from CLK10
controller = -1;    /* Local controller */
mode = 0;                /* Initialize the counter */
source = 70;             /* CLK10 */
count = 1000;
ret = TrigCntrConfig (controller, mode, source, count);
/* Use SrcTrig() to start the counter */
line = 50;               /* 16-bit Counter */
prot = 4;                /* SYNC, to start */
timeout = 0L;            /* No timeout */
ret = SrcTrig (controller, line, prot, timeout);

If the counter is reconfigured with the initialization mode, a call to EnableTrigSense() or SrcTrig() is again required to start the count. If the counter is simply reloaded using the reload mode, the counter begins counting immediately upon being reloaded. At any point, TrigCntrConfig() can be called to abort or disable the counter with the disable mode.

Although it is true that both EnableTrigSense() and SrcTrig() can start the counter, they have a different emphasis. Because it is possible to have the trigger lines as the source of the counter clock, it is possible to count trigger assertions. By configuring the counter with the correct count, mapping its inputs and outputs, and starting it with EnableTrigSense(), the counter can be programmed to count any of the protocols, rather than sourcing them. Example 8 shows sample code for setting the counter to count multiple SYNC trigger assertions.

Example 8 Counting Triggers with the TIC Counter
controller = -1; /* Local controller */
mode = 0; /* Initialize the counter */
source = 0; /* Clock the counter from TTL0 */
count = 10;
ret = TrigCntrConfig (controller, mode, source, count);

/* Use EnableTrigSense() to enable the counter */
line = 50; /* TIC counter */
prot = 4; /* SYNC */
ret = EnableTrigSense (controller, line, prot);

Once the count is complete, GCNTR will assert and you can have the TIC generate an interrupt for your program.

TIC Timer Functions
Besides the 16-bit counter, there are two 5-bit counters, known as the TICK timers, which use the 5-bit value as the power of two for the count. Like the 16-bit counter, the TICK timers also have different modes that they can be configured for. However, the TICK timers differ in that they can be initialized in one of two different modes: rollover or non-rollover. Rollover mode causes the counter to be reloaded automatically at the end of the count without software intervention. Non-rollover mode causes the counters to cease operation when the count is finished.

Example 9 Using the TIC Timers
controller = -1;/* Local controller */
mode = 1;           /* Initialize the counter, non-rollover
                         mode */
source = 70;        /* CLK10 */
tcount1 = 3;        /* 2 to the 3rd power */
tcount2 = 0;        /* Does not matter */
ret = TrigTickConfig (controller, mode, source, tcount1,
                    tcount2);
line = 60;          /* TIC TICK timers */
prot = 4;           /* SYNC */
timeout = 0L;       /* No timeout */
ret = SrcTrig (controller, line, prot, timeout);


As shown in Example 9, setting the value to 3 causes the TICK timer to count eight input pulses (23) before terminating. Notice that SrcTrig() is used to start the timer in the same way that it is used by the 16-bit counter. Also, using the TrigTickConfig() function, you can program the TICKs to count from the CLK10 signal, the EXTCLK input, or any of the external GPIO lines.

The output of the TICK timers is a square wave with a period of the count value in clock pulses. If the counter is set to 3, resulting in a count of eight, the TICK output would be high for four counts and low for four counts. If the timer is clocked from the CLK10 signal with rollover mode, a count of eight would result in an 800 ns period square wave (1.25 MHz). See Example 10.

Example 10 Generating Continuous Square Waves with the TIC Timers
controller = -1;/* Local controller */
mode = 0;           /* Initialize the counter, rollover mode */
source = 70;        /* CLK10 */
tcount1 = 3;        /* 2**3 */
tcount2 = 0;        /* Does not matter */
ret = TrigTickConfig (controller, mode, source, tcount1,
tcount2);

line = 60;          /* TIC TICK Timers */
prot = 4;           /* SYNC */
timeout = 0L;       /* No time-out */
ret = SrcTrig (controller, line, prot, timeout);

The TICK timers are integrated in their operation. The first TICK counter, TICK1, actually controls the counter circuitry. When TICK1 completes its count (assuming non-rollover mode), the counter circuitry is disabled, whether or not TICK2 has completed its count. You can use this feature to generate square waves for a specific amount of time by entering the desired

frequency of the square wave in TICK2, and the length of the square wave in TICK1 (with non-rollover mode selected). The resulting TICK2 output is a 50 percent duty cycle square wave up to the last count6. The following code will generate a 400 ns square wave for 51.2 ms out of the TICK2 output.

Example 11 Generating Finite Length Square Waves with the TIC Timers
controller = -1;/* Local controller */
mode = 1;           /* TICK1 for non-rollover so it will */
               /* end with the end of the count */
source = 70;        /* CLK10 */
tcount1 = 10;
tcount2 = 2;
ret = TrigTickConfig (controller, mode, source, tcount1,
                         tcount2);

line = 60;          /* TIC TICK timers */
prot = 4;           /* SYNC */
timeout = 0L;       /* No timeout */
ret = SrcTrig (controller, line, prot, timeout);

LabVIEW Implementation of NI-VXI
When using LabVIEW, all NI-VXI virtual instruments (VIs) make calls to the main NI-VXI library (DLL, or dynamic link library for Windows; .so, or shared object files for Sun or HP-UX; and the Device Manager on Macintosh). Because of this, there is a LabVIEW VI for every NI-VXI function discussed so far. LabVIEW differs from the NI-VXI trigger functions only in how to deal with interrupts. LabVIEW has two approaches for installing a user-written interrupt handler.

The first approach is to use the  PollTrigHandler() 7 VI, which waits until a trigger interrupt has occurred and then continues. This is similar to the WaitForTrig() function, but differs mainly in the return information provided. This return information for PollTrigHandler() is the same as an interrupt handler would receive.

The second approach in LabVIEW is to use the LabVIEW feature of occurrences. An occurrence is a tool that can block execution at multiple points in a LabVIEW program until a certain event occurs. Using this, you can pause different execution flows until an interrupt occurs. Using the SetTrigHandler VI, you can tell LabVIEW to generate an occurrence when a trigger interrupt occurs. Please refer to the LabVIEW documentation for more information on occurrences.

LabWindows/CVI Implementation of NI-VXI
LabWindows/CVI is a complete, full-function C programming environment for PC-compatible computers running Windows and for Sun SPARCstations. Because LabWindows/CVI calls NI-VXI directly, you do not have to account for any compatibility issues. You can use all the NI-VXI functions designed for C platforms without alteration in the LabWindows/CVI environment.

GPIB-VXI Implementation of NI-VXI
The GPIB-VXI models, including the /C and /CP models, have the capability to control and respond to triggers. Although there are no GPIB commands equivalent to the VXIbus trigger capability, the GPIB-VXI from National Instruments does come with its own local command set that you can use to program for a wide variety of VXIbus features, including triggering. In addition, the /C and /CP models have the TIC chip onboard. The local command set is simply a set of string commands that the GPIB-VXI parses and executes. Example 12 shows the NI-VXI command to source TTL0 with the SYNC protocol (in C).

Example 12 Using the GPIB-VXI Local Command Set for Triggering
ret = SrcTrig (-1, 0, 4, 0L);

whereas using IEEE 488.2 commands on a GPIB-VXI, it would look like

Send (boardID, GPIBAddress, "SrcTrig 0, 4, 0", NLend);

and the IEEE 488.1 command would be,

ibwrt (deviceID, "SrcTrig 0, 4, 0", 15);

The local command set is functionally equivalent to the NI-VXI API, and in most cases the functions themselves are identical. The names of the API may differ occasionally due to differences in the abbreviations; for example, AcknowledgeTrig() becomes AckTrig. But the parameter lists for the functions are the same except that the GPIB-VXI does not need the controller parameter used by the NI-VXI API.

The GPIB-VXI controller also has an extra command for use with the SRQ line in the GPIB cable. The local command TrigToREQT causes the SRQ line to be asserted if a specified TTL trigger, ECL trigger, or counter output becomes asserted. Not only does the GPIB-VXI assert the SRQ line and respond to the serial poll, but you can also use TrigToREQT to specify which logical address should be credited with asserting the SRQ. As a result, you can have multiple devices asserting triggers, and hence SRQ, and have the serial poll information returned to indicate the source of the trigger.

Understanding the SEMI-SYNC Trigger Protocol


The SEMI-SYNC protocol is a single source, multiple acceptor protocol that can be used to set up a wide variety of synchronization between VXIbus instruments. Because NI-VXI is still capable of supporting the SEMI-SYNC protocol from Revision 1.3 of the VXIbus specification, and the wired-OR glitch problem with the protocol does not occur when there is a single acceptor, the functionality is described in this document.

Software Sourcing and Acknowledging
This is the simplest implementation of SEMI-SYNC that you can do, and is the only method on platforms without the TIC chip. To have the controller source the protocol, you can use SrcTrig() with the choice to either wait until the protocol has completed, or to start the protocol and return. In this case, you can use WaitForTrig() to determine whether the protocol has completed, or you can use SetTrigHandler() to install your own interrupt handler to respond when the protocol has completed. For more information, refer to the Program Control subsection of the NI-VXI Solutions to VXIbus Triggering section earlier in this document.

If the controller is to participate as an acceptor in the protocol, call EnableTrigSense() to have an interrupt generated when protocol is detected. The trigger line is automatically driven until AcknowledgeTrig() is called. Notice that you do not need to explicitly call AcknowledgeTrig() because the default interrupt handler will do this for you. However, if you use SetTrigHandler() to install your own handler to be called when the protocol begins, your program needs to call AcknowledgeTrig().

Automatic Source/Acknowledge via the Counter
It is possible to have the 16-bit counter of the TIC chip automatically source or acknowledge multiple SEMI-SYNC protocols. This can be useful when the protocol is being used to sequence instruments through several steps in some automatic process. For example, if you know that your program is to perform a specific task on the third step of the process—but not on the first or second step—you can program the counter to acknowledge the protocol twice, and interrupt the program on the third protocol assertion, allowing the program to perform its task and acknowledge the protocol. In the reverse view, if you are the one to sequence the instruments, you can program the counter for the number of steps you need to sequence through before you take any action, such as reading the acquired data.

To program the counter to source multiple SEMI-SYNC protocols, you first call
TrigCntrConfig() with the number of times to source SEMI-SYNC and the trigger line to use. Then a call to SrcTrig()—not EnableTrigSense()—with the protocol set to SEMI-SYNC begins the sequence. The code automatically configures the TIC chip to have the counter generate an assertion edge after the call to SrcTrig() and not reassert the protocol until it detects the completion of the current one. When all the acceptor devices have stopped driving the trigger line, the rising edge of the line causes the counter to decrement, thus generating another trigger off the TCNTR output8. (For more information on the counter operation refer to the TIC Counter Functions subsection in the previous section, NI-VXI Solutions to VXIbus Triggering, or Appendix A, The TIC Chip.) Notice, however, that NI-VXI handles all of the routing required for the counter. All you must indicate is the line from which to clock the counter and what protocol to use—the rest is done automatically. For example, to have the counter generate 10 SEMI-SYNC protocols on TTL1, you can use the code shown in Example 13.

Example 13 Having the TIC Counter Generate SEMI-SYNC Protocols
controller = -1;/* Local controller */
mode = 0;           /* Initialize the counter */
source = 1;         /* Let TTL1 clock the counter */
count = 10;         /* Ten protocols to count */
ret = TrigCntrConfig (controller, mode, source, count);

line = 50;          /* TIC counter */
prot = 5;           /* SEMI-SYNC */
timeout = 0L;       /* No timeout */
ret = SrcTrig (controller, line, prot, timeout);

Notice that the trigger line that will transmit the SEMI-SYNC protocol is used to actually clock the counter. This is important because you do not want to generate the next trigger until the last one has completed.

In contrast, to acknowledge multiple protocols you again call TrigCntrConfig() with the number of protocols you want automatically acknowledged, plus the one to which you want to respond. The call to  EnableTrigSense() instead of SrcTrig() causes the TIC chip to automatically participate in the protocol, asserting the trigger line for 100 ns at a time. When the last SEMI-SYNC is reached, the TIC holds the trigger line asserted and generates an interrupt. The default interrupt handler automatically completes the last protocol unless you use SetTrigHandler() to install your own handler to perform some action and then complete the final protocol with AcknowledgeTrig().

Remote Acknowledge
The final way to use the SEMI-SYNC protocol with the TIC chip is to have it convert the SEMI-SYNC protocol to a two-wire ASYNC handshake with another device. This means the TIC is not an actual acceptor, but instead a translator between two devices. When the TIC chip detects the assertion edge of the SEMI-SYNC protocol, you can have it assert the SEMI-SYNC trigger line and send the original assertion out an external GPIO line, such as the Front Out connector. This can then be connected to a device that generates an acknowledge on a second line. This line is brought in through another external GPIO line, such as the Front In connector, and automatically causes the TIC to stop asserting the SEMI-SYNC trigger line, thus allowing the protocol to complete. Notice that all of this is done without software intervention. The GPIO and Trigger modules and the crosspoint switch make it possible for the entire process to be handled by hardware.

The following example shows the calls to have the SEMI-SYNC protocol arrive on TTL0 to be converted to an ASYNC handshake using GPIO0 (Front In) and GPIO1 (Front Out). The first function call is to TrigAssertConfig() where you specify the trigger line where the SEMI-SYNC protocol is to occur and set the mode flag to tell the line to participate in the SEMI-SYNC protocol with external trigger acknowledge. You then use the combination of TrigExtConfig() and  MapTrigToTrig() to configure each of the two GPIO lines that will participate in the external ASYNC handshake. The TIC chip is now ready to perform the SEMI-SYNC remote acknowledge.

Example 14 Doing a Remote Acknowledge of SEMI-SYNC Protocol
controller = -1;/* Local controller */
line = 0;           /* TTL0 */
mode = 6;           /* Pass the SEMI-SYNC assert edge */
                    /* through without synchronizing with */
                    /* CLK10 and participate in the */
                    /* SEMI-SYNC with external acknowledge  */
ret = TrigAssertConfig (controller, line, mode);

extline = 40;       /* Front In - GPIO0 */
mode = 0;           /* Set tristated for map */
ret = TrigExtConfig (controller, extline, mode);
extline = 41;       /* Front Out - GPIO1 */
mode = 0;           /* Set tristated for map */
ret = TrigExtConfig (controller, extline, mode);

SrcTrigger = 0;     /* Map from TTL0 */
destTrig = 41;      /* Front Out - GPIO1 */
mode = 0;           /* No signal conditioning */
ret = MapTrigToTrig (controller, SrcTrigger, destTrig, mode);

SrcTrigger = 40;/* Map from Front In - GPIO0 */
destTrig = 0;       /* TTL0 */
ret = MapTrigToTrig (controller, SrcTrigger, destTrig, mode);

Appendix A the TIC Chip


This appendix describes the components that make up the TIC chip. Figure 7 is the TIC block-level diagram.


Figure 7. TIC Chip Block Diagram

There are four important sets of lines:
  • External GPIO
  • External trigger
  • GPIN
  • TRIGIN

The external GPIO lines are external general-purpose input/output lines that can be connected to a wide variety of lines outside the chip, but enter the chip through the GPIO modules. For example, with the 486-based embedded computers, GPIO0 is connected to the Front Panel In line and GPIO1 is connected to the Front Panel Out line. The external GPIO lines give the TIC chip the flexibility to control more than just the trigger lines.

The external GPIO lines are external general-purpose input/output lines that can be connected to a wide variety of lines outside the chip, but enter the chip through the GPIO modules. For example, with the 486-based embedded computers, GPIO0 is connected to the Front Panel In line and GPIO1 is connected to the Front Panel Out line. The external GPIO lines give the TIC chip the flexibility to control more than just the trigger lines.

The trigger lines themselves also enter in the chip through the Trigger modules. Ten trigger lines can enter the TIC chip, with TTL0-7 and ECL0-1 currently connected9. Once inside the chip, these lines are conditioned and multiplexed by the GPIO and Trigger modules, which then output them as the GPIN and TRIGIN lines, respectively. Notice that the GPIN and TRIGIN lines are completely internal to the chip.

The GPIN and TRIGIN lines feed into the crosspoint switch to provide mapping to and from the various external lines. The crosspoint switch block is simply an abbreviation for the fact that all GPIN and TRIGIN lines are wired to go to all the Trigger and GPIO modules. The remaining blocks are the CPU interface which gives the TIC access to the computer and its interrupts, the 16-bit counter, and the two TICK timers (shown as the Scalar block).

Counter
The counter block is a 16-bit counter that is available to the user. It has two outputs—GCNTR and TCNTR. GCNTR is asserted when the counter completes its count by counting from 1 to 0, and stays asserted until the counter is reset. TCNTR generates a 100 ns pulse with each counter clock edge. Both GCNTR and TCNTR are shown in Figure 7 as the signal CNTROUT. You can program the TIC to interrupt the CPU when the counter has finished counting down (the GCNTR signal is asserted).

The counter is useful not only in chronological measurement, but also as a trigger counter. Example 8 earlier in this document shows how to set the counter to count 10 assertions of trigger line TTL0. This can be useful in cases where the controller is attempting to synchronize itself with other devices in the chassis. For example, if another device is sequencing a state machine by asserting the trigger line, the sample code in Example 8 can be used to tell the controller when it is time for it to perform some action.

If the counter is being reloaded and left enabled, it is not necessary to call either SrcTrig() or EnableTrigSense() because the counter begins its count immediately after the call to TrigCntrConfig() with the reload mode option. However, the counter does not have an automatic reload-and-start mode (rollover), so it must be reloaded explicitly after counting down to 0. To facilitate in reloading, you can program the TIC to interrupt the CPU when the terminal count has been reached, enabling you to reload the counter with another call to TrigCntrConfig(). See Example 4 for sample code on interrupts.

See the TIC Counter Functions subsection of the NI-VXI Solutions to VXIbus Triggering section for more information on these and other uses of the counter.

Scalar
This block contains the two 5-bit timers TICK1 and TICK2. The counter equation

count = 2 X

is calculated from the X value, which is stored in the timer. Therefore the timer can count to values from 1 to 2 32. Both TICK timers have a single output (TICK1OUT or TICK2OUT) which changes state halfway through the count. For example, if TICK1 is programmed with the value 3, which is an 8 count, it counts for four input pulses (2 3/ 2) and then changes its output from a 1 to a 0, where it counts the last four input pulses. Example 9, given previously, illustrates how to generate a single period of a square wave for the eight clock cycles, or in this case, 800 ns.

Like the 16-bit counter, both SrcTrig() and EnableTrigSense() can be used to start the timers. However, using SrcTrig() will cause the TICK timers to run without interrupts being generated when TICK1 has finished its count.

A common use for the TICK timers is in continuous square wave generation. If a counter is programmed for rollover mode, it automatically reloads at the end of the count and starts again. This means that the counter value determines the period of the square wave generated. To continue the example from above, assume the timer is programmed for rollover mode. After it has counted down to 0 it reloads, sending the output high again, and repeats the cycle. The resulting output is a square wave with a period of eight clock cycles, or 800 ns. This is shown in Example 10.

You can also have a square wave generated for a specified amount of time. This is possible because TICK1 actually controls the timer mechanism. When TICK1 has completed its count, it shuts down the counter mechanism. Therefore, by programming TICK1 with the length of time the square wave should run, and TICK2 with the period of the square wave, you can obtain a precise length square wave10. For instance, Example 11 generates a square wave with a four-clock cycle period (400 ns) for 210 clock cycles.

Trigger Module
Refer to Figure 8 as you review this section. Notice that there are actually 10 such trigger modules as shown in Figure 7. At this level, however, the Trigger module is connected only to one external trigger line, through the Trigger pad.


Figure 8. TIC Trigger Module

Although the diagram in Figure 8 may look daunting, it is relatively simple. First break the diagram into an upper and lower half as shown by the dotted line, with the upper half being the output of a signal onto the Trigger pad (the TTL0-7 and ECL0-1 lines), and the lower half being the routing of the external trigger lines into the crosspoint switch11.

For the upper block, the diagram starts by allowing the chip to select from any of the GPIN lines from the GPIO modules, either of the TICK timer outputs, or the TCNTR output of the 16-bit counter. Remember that the GPIN lines are not the external GPIO lines, but are the output lines of the GPIO modules. The output goes either into the SEMI-SYNC ACK HW circuitry or through the clock synchronization circuitry. If the SEMI-SYNC protocol is active, the assertion of the HWIN line is used for the hardware acknowledge of the SEMI-SYNC protocol. (Refer to the Understanding the SEMI-SYNC Trigger Protocol section for more information.) The clock synchronization route allows for a software assertion of the associated trigger line either through the ASSERT line (a bit in a control register of the TIC) or by the line mapped in as HWIN. The option that NI-VXI selects depends on whether you have used MapTrigToTrig() to drive the trigger line from another line, or SrcTrig() to drive the line via software.

Once the signal is passed through the OR gate, it branches into two lines that go either through two data flip-flops or directly to a multiplexer. The multiplexer decides (from the TSYNC bit in a TIC register) which signal to pass onto the backplane. If the generation of the trigger is to be synchronous with the CLK10, the upper route is selected. The flip-flops are clocked by CLK10 and cause the trigger to be synchronized with the clock. If synchronization is not selected, the trigger signal passes straight through the lower route to the multiplexer. Which route is chosen depends on the call to TrigAssertConfig(), which uses the mode parameter to select the route.

Notice that at this point, the output of the multiplexer is ORed with the output of the SEMI-SYNC ACK HW circuitry resulting in a single TRIGOUT signal. It is this signal that is finally driven out of the chip and onto the external trigger line.

The lower half of the diagram in Figure 8 brings the external trigger line into the TIC chip and through to the crosspoint switch. After the trigger line is brought in from the trigger pad and buffered, it branches to four locations. Two branches go to the assertion and unassertion edge detectors. These are used in trigger sensing and give the TIC chip the ability to interrupt the CPU when a trigger protocol is detected. AOVER and UOVER are bits in a status register of the TIC and report assertion and unassertion overruns. These overrun conditions can be detected via the trigger interrupt handler, which reports on the status of the TIC chip.

The final section of this module is the multiplexer that actually generates the TRIGIN signal. Although all inputs to the multiplexer come from the trigger pad, and hence an external trigger line, signal conditioning circuitry makes it possible to modify the trigger signal. All of these modifications are accessible from NI-VXI when the MapTrigToTrig() function is used to map the external trigger line to another line. The options consist of either sending the signal through with no conditioning, synchronizing the signal with the CLK10 or EXTCLK signal, or pulse-stretching the signal to a minimum length. Pulse stretching is a feature of the TIC chip that allows any pulse to be extended to meet settling or setup time requirements for the target device.

For example, assume that you are going to map the trigger signal out through an external GPIO line to another device. The original trigger signal is a 10 ns pulse but your device requires at least a 100 ns pulse. You can pulse stretch the original trigger signal to 100 ns by selecting either the Asynchronous 1clk or Synchronous 1clk pulse-stretch options. These options stretch the trigger signal to be at least one clock length, using either CLK10 or EXTCLK. The difference between the two pulse-stretch options is that Asynchronous 1clk means the start of the pulse on TRIGIN corresponds directly to the original assertion. Synchronous 1clk delays the TRIGIN assertion until the next clock edge. Either way, a one-clock length minimum is imposed on the TRIGIN pulse.

GPIO Module
Like the Trigger module, the GPIO module can either drive an external GPIO line or map the external GPIO line into the crosspoint switch. Unlike the Trigger module, it cannot do both at the same time. However, the GPIO module does have an extra capability that allows it to feed the module input back into the crosspoint switch. This section discusses each of these options. Please see Figures 7 and 9 for this discussion.


Figure 9. TIC GPIO Module

Figure 9 illustrates the GPIO module. Each GPIO module is connected to only a single external GPIO line through the GPIO pad. However, the module input can select from any of the TRIGIN lines from the Trigger modules, the GCNTR signal from the 16-bit counter, or the TICK2 counter output. Which input is selected depends on the parameters of the MapTrigToTrig() function. Once the input has been selected, it can either pass directly out to the external GPIO line through the GPIO pad, or have signal conditioning applied first. This conditioning consists of inverting the polarity of the signal by the POLOUT bit and allowing for software assertions through the ASSERT bit. You can select any of these options through the TrigExtConfig() function. Notice that the input referred to by the mode parameter of this function refers to the input to the GPIO module, and the external input refers to the external GPIO line.

If the module brings the GPIO signal into the TIC chip, it is brought in through the GPIO pad and made available for signal conditioning. As you can see from Figure 9, the signal can either be asserted through software or have its polarity inverted before being sent into the crosspoint switch as GPIN. Again, TrigExtConfig() controls these settings. See Example 5 earlier in this document for examples on mapping external lines.

Besides routing a signal into or out of the chip with the external GPIO line, a third option is available for the GPIO module. Figure 9 shows that the signal that propagates from the crosspoint switch and out to the GPIO pad also has a route that circles back toward the GPIN line. This route is what allows the GPIO module to feed its input back to its output, giving it the ability to map trigger lines to trigger lines. The module has a multiplexer that is controlled by the Feedback Select signal. If feedback is selected by the TrigExtConfig() function, this multiplexer, in addition to buffers at other points in the module, redirects the signal mapped into the GPIO module back to the crosspoint switch. Therefore, if TTL0 is mapped to GPIO9, which has feedback selected, you can map GPIO9 to TTL1 and cause an electrical connection between TTL0 and TTL1. This means that any signal on TTL0 would appear on TTL1 automatically, without software intervention. Example 6, given previously in this document, shows the code to provide the connection.

Appendix B Example Using the TIC Counter to Implement Program Delay


On a PC platform, most languages include a delay function to temporarily halt the execution of the program for a specified amount of time. These functions rely on the PC system clock which runs at 18 Hz, resulting in a 55 ms resolution timer. In some situations, it is necessary to have a delay function with a higher resolution. The following program creates a delay function with a resolution of 1 ms for use in a standalone DOS executable. It takes advantage of the TIC counter to interrupt the program every 1 ms. Of course, there are several ways in which to have the TIC chip provide this feature, but this one requires only the TIC counter and no trigger lines.
Another advantage of this function is that it does not require any special setup. All you need to do is call TIC_Delay() as you would normally call the Delay() function.

#include "nivxi.h"
#include <stdio.h>
#include <process.h>

#define CONTROLLER -1
#define SET_TRIG_HNDR 1U<<14
#define GET_TRIG_HNDR 50
#define SYNC   4
#define CLK10 70
#define ONE_MS_COUNT  10000U  /* number of CLK10 cycles that = 1 ms */

#define NO_ERROR0

static int16 ret;

/* Interrupt Flag and Function */
static int delay_flag=0;

NIVXI_HQUAL void NIVXI_HSPEC delay_intr_handler (int16, uint16,
uint16);
NIVXI_HQUAL void NIVXI_HSPEC (*old_handler) (int16, uint16, uint16);

/**************/
/*
/* TIC_Delay -- 1 ms res. delay function using interrupts
/*
/**************/
int TIC_Delay (uint16 count)
{
    uint16 loop;

    /**/
     /* Enable the Interrupts.  Notice the return codes have an
    /* extra number subtracted to more easily identify the
    /* function that returned the error code.
    /* Also notice that the old handler is retrieved first so that
     /* it may be reinstalled at the end of the delay function.

     /**/
     old_handler = GetTrigHandler (GET_TRIG_HNDR);

    ret = SetTrigHandler (SET_TRIG_HNDR, delay_intr_handler);
    if (ret<0) return ret;
    ret = TrigCntrConfig (CONTROLLER, 0, CLK10, ONE_MS_COUNT);
     if (ret<0) return ret - 200;
     ret = EnableTrigSense (CONTROLLER, 50, SYNC);
     if (ret<0) return ret - 400;


     /**/
    /* Respond to count interrupts.
     /**/
    for (loop=0; loop<count; loop++) {

        while (!delay_flag);     /* Waiting for interrupt */
         delay_flag = 0;

     }

    ret = DisableTrigSense (CONTROLLER, 50);
     if (ret<0) return ret - 800;
    ret = SetTrigHandler (SET_TRIG_HNDR, old_handler);
     if (ret<0) return ret - 1000;

    return 0;

} /* END TIC_Delay () */

NIVXI_HQUAL void NIVXI_HSPEC delay_intr_handler (int16 controller,
uint16 line, uint16 type)
{
    delay_flag = 1;

    /* Reset the 16-bit Counter */
    TrigCntrConfig (CONTROLLER, 2, CLK10, ONE_MS_COUNT);

} /* END delay_intr_handler */

void main(void)
{

    /* It is not recommended to call InitVXIlibrary() in the  */
    /* Delay function because the overhead on InitVXIlibrary() */
    /* can be fairly large. */
    ret = InitVXIlibrary();
    if (ret<0) {
         printf ("Init Failed\n");
        exit (-1);
     }

    /* Delay for 1 ms */
    printf("First for 1 ms...\n");

   TIC_Delay (1);

   /* Delay for 100 ms */
   printf("Done, now for 100 ms...\n");
   TIC_Delay (100);
   printf("Done!\n");

   ret = CloseVXIlibrary();

}