Miscellaneous VXI Interface Programming

This section contains information specific to the Windows product.

This section provides other information for programming via the VXI interface, including the following subtopics:

Communicating with VME Devices

Although VXI is an extension of VME, VME is not easy to use in a VXI system. Since the VXI standard defines specific functionality that would be custom designs in VME, some resources required for VME custom design are actually used by VXI. Therefore, there are certain limitations and requirements when using VME in a VXI system.

NOTE: VME is not an officially supported interface for SICL and is not supported over LAN.

Use these processes when using VME devices in a VXI mainframe:

  • Declare resources
  • Map VME Memory
  • Read and write device registers
  • Unmap memory
  • Use VME interrupts

Declaring Resources

The VXI Resource Manager does not reserve resources for VME devices. Instead, a configuration file is used to reserve resources for VME devices in a VXI system. Use the VXI Device Configurator to edit the DEVICES file (or edit the file directly) to reserve resources for VME devices. The VXI Resource Manager reads this file to reserve the VME address space and VME IRQ lines. The VXI Resource Manager then assigns the VXI devices around the already reserved VME resources.

For VME devices requiring A16 address space, the device’s address space should be defined in the lower 75% of A16 address space (addresses below 0xC000). This is necessary because the upper 25% of A16 address space is reserved for VXI devices.

For VME devices using A24 or A32 address space, use A24 or A32 address ranges just higher than those used by your VXI devices. This will prevent the VXI Resource Manager from assigning the address range used by the VME device to any VXI device. (The A24 and A32 address range is software programmable for VXI devices.)

Mapping VME Memory

SICL defaults to byte, word, and longword supervisory access to simplify programming VXI systems. However, some VME cards use other modes of access that are not supported in SICL. Therefore, SICL provides a map parameter that allows you to use the access modes defined in the VMEbus Specification. See the VMEbus Specification for information on these access modes.

NOTE: Use care when mixing VXI and VME devices. You must know the VME address space and offset within that address space the VME devices use. VME devices cannot use the upper 16K of the A16 address space since this area is reserved for VXI instruments.

When accessing VME or VXI devices via an embedded controller, current versions of SICL use the “supervisory data” address modifiers 0x2D, 0x3D, and 0x0D for A16, A24, and A32 accesses, respectively. (Some older versions of SICL use the “non-privileged data” address modifiers.)

Use the I_MAP_AM | address modifier map space argument in the imap function to specify the map space region (address modifier) of VME address space. See the VMEbus Specifications for information on values to use as the address modifier. If the controller does not support the specified address mode, the imap call will fail (see table in the next section).

This maps A24 non-privileged data access mode:

prt = imap (id, (I_MAP_AM | 0x39), 0x20, 0x4,
0);

This maps A32 non-privileged data access mode:

prt = imap (id, (I_MAP_AM | 0x09), 0x20, 0x40,
0);

This table lists VME access modes supported on Keysight controllers.

VME Mapping Support

 

         A16
(D08,  D16 , D32)

        A24
 (D08, D16 , D32)

        A32
(D08, D16 , D32)

Supervisory data

x x x

Non-privileged data

 

 

 

Reading and Writing Device Registers

After you have mapped the memory space, use the SICL i?peek and i?poke functions to communicate with the VME devices. With these functions, you need to know the register to communicate with and the register’s offset.

See the instrument’s user’s manual for descriptions of registers and register locations. This is an example using iwpeek:

id = iopen (“vxi”);
addr = imap (id, (I_MAP_AM | 0x39), 0x20, 0x4,
0);
reg_data = iwpeek ((unsigned short *)(addr +
0x00));

Unmapping Memory Space

Make sure you use the iunmap function to unmap the memory space when it is no longer needed. This frees the mapping hardware so it can be used by other processes.

VME Interrupts

There are seven VME interrupt lines that can be used. By default, VXI processing of the IACK value will be used. However, if you configure VME IRQ lines and VME Only, no VXI processing of the IACK value will be done. That is, the IACK value will be passed to a SICL interrupt handler directly.

Sample: VME Interrupts (C)

This ANSI C sample program opens a VXI interface session and sets up an interrupt handler. When the I_INTR_VME_IRQ1 interrupt occurs, the function defined in the interrupt handler is called. The program then writes to the registers, causing the I_INTR_VME_IRQ1 interrupt to occur.

You must edit this program to specify the starting address and register offset of your specific VME device. This sample program also requires the VME device to be using I_INTR_VME_IRQ1, and the controller to be the handler for the VME IRQ1.

/* vmedev.c
 This example program opens a VXI interface session and sets up an interrupt handler. When the specified interrupt occurs, the procedure defined in the interrupt handler is called. You must edit this program to specify starting address and register offset for your specific VME device. */

#include <stdio.h>
#include <stdlib.h>
#include <sicl.h>

#define ADDR “vxi”

void handler (INST id, long reason, long secval){
printf (“Got the interrupt\n”);
}

void main ()
{
unsigned short reg;
char *base_addr;
INST id;

/* install error handler */
ionerror (I_ERROR_EXIT);

/* open an interface communications session */
id = iopen (ADDR);
itimeout (id, 10000);

/* install interrupt handler */
ionintr (id, handler);
isetintr (id, I_INTR_VME_IRQ1, 1);

/* turn interrupt notification off so that
interrupts are not recognized before the
iwaithdlr function is called*/
iintroff ();

/* map into user memory space */
base_addr = imap (id, I_MAP_A24, 0x40, 1,
NULL);

/* read a register */
reg = iwpeek((unsigned short *)(base_addr +
0x00));

/* print results */
printf (“The registers contents were as
follows: 0x%4X\n”, reg);

/* write to a register causing interrupt */
iwpoke ((unsigned short *)(base_addr + 0x00),
reg);

/* wait for interrupt */
iwaithdlr (10000);

/* turn interrupt notification on */
iintron ();

/* unmap memory space */
iunmap (id, base_addr, I_MAP_A24, 0x40, 1);

/* close session */
iclose (id);
}

VXI Backplane Memory I/O Performance

SICL supports two different memory I/O mechanisms for accessing memory on the VXI backplane.

VXI Supported Memory I/O Mechanisms

Single location peek/poke and direct memory dereference

imap, iunmap, ibpeek, iwpeek, ilpeek, ibpoke, iwpoke, ilpoke, value = *pointer, *pointer = value

Block memory access

imap, iunmap, ibblockcopy, iwblockcopy, ilblockcopy, ibpushfifo, iwpushfifo, ilpushfifo ibpopfifo, iwpopfifo, ilpopfifo

Using Single Location Peek/Poke

Single location peek/poke or direct memory dereference is the most efficient in programs that require repeated access to different addresses. On many platforms, the peek/poke operations are actually macros which expand to direct memory dereferencing.

An exception is Windows platforms, where ipeek/ipoke are implemented as functions since (under certain conditions) the compiler will attempt to optimize a direct dereference and cause a VXI memory access of the wrong size.

For example, when masking the results of a 16-bit read in an expression:

data = iwpeek(addr) & 0xff;

the compiler will simplify this to an 8-bit read of the contents of the addr pointer. This would cause an error when attempting to read memory on a VXI card that did not support 8-bit access. When iwpeek is implemented as a function, the correct size memory access is guaranteed.

Using Block Memory Access

The block memory access functions provide the highest possible performance for transferring large blocks of data to or from the VXI backplane. Although these calls have higher initial overhead than the ipeek/ipoke calls, they are optimized on each platform to provide the fastest possible transfer rate for large blocks of data.

These routines may use DMA, which is not available with ipeek/ipoke. For small blocks, the overhead associated with the block memory access functions may actually make these calls longer than an equivalent loop of ipeek/ipoke calls.

The block size at which the block functions become faster depends on the particular platform and processor speed.

Sample: VXI Memory I/O (C)

A code sample follows that demonstrates the use of simple and block memory I/O methods in SICL.

/*
siclmem.c
This example program demonstrates the use of simple and block memory I/O methods in SICL. */

#include <sicl.h>
#include <stdlib.h>
#include <stdio.h>

#define VXI_INST “vxi,24”

void main () {
INST id;
unsigned short *memPtr16;
unsigned short id_reg;
unsigned short devtype_reg;
unsigned short memArray[2];
int err;

/* Open a session to the instrument */
id = iopen(VXI_INST);

/* ============== Simple memory I/O==========
= iwpeek()
= direct memory dereference

On many platforms, the ipeek/ipoke operations
are actually macros which expand to direct
memory dereferencing. The exception is on
Microsoft Windows platforms where ipeek/ipoke
are implemented as functions.

This is necessary because under certain
conditions, the compiler will attempt to
optimize a direct dereference and cause a VXI
memory access of the wrong size. For example,
when masking the results of a 16-bit read in a
expression:

data = iwpeek(addr) & 0xff;

the compiler will simplify this to an 8-bit
read of the contents of the addr pointer. This
would cause an error when attempting to read
memory on a VXI card that did not support 8-bit
access. */

/* Map into memory space */
memPtr16 = (unsigned short *)imap(id,
I_MAP_VXIDEV, 0, 1, 0);

/* ============ Using Peek ================= */

/* Read instrument id register contents */
id_reg = iwpeek(memPtr16);

/* Read device type register contents */
id_reg = iwpeek(memPtr16+1);

/* Print results */
printf(“ iwpeek: ID Register = 0x%4X\n”,
id_reg);
printf(“ iwpeek: Device Type Register =
0x%4X\n”, devtype_reg);

/* Use direct memory dereferencing */
id_reg = *memPtr16;
devtype_reg = *(memPtr16+1);

/* Print results */
printf(“dereference: ID Register = 0x%4X\n”,
id_reg);
printf(“dereference: Device Type Register =
0x%4X\n”, devtype_reg);

/* =============== Block Memory I/O ==========
= iwblockcopy
= iwpushfifo
= iwpopfifo

These commands offer the best performance for
reading and writing large data blocks on the
VXI backplane. For this example, we are only
moving 2 words at a time. Normally, these
functions would be used to move much larger
blocks of data. */

/* ======== Demonstrate Block Read ======== */

/* Read the instrument id register and device
type register into an array. */

err = iwblockcopy(id, memPtr16, memArray, 2,
0);

/* Print results */
printf(“ iwblockcopy: ID Register = 0x%4X\n”,
memArray[0]);
printf(“ iwblockcopy: Device Type Register =
0x%4X\n”, memArray[1]);

/* ======= Demonstrate popfifo =============*/

/* Do a popfifo of the Id Register */
err = iwpopfifo(id, memPtr16, memArray, 2, 0);

/* Print results */
printf(“ iwpopfifo: 1 ID Register = 0x%4X\n”,
memArray[0]);
printf(“ iwpopfifo: 2 ID Register = 0x%4X\n”,
memArray[1]);

/* ============ Cleanup and Exit ==========*/

/* Unmap memory space */
iunmap(id, (char *)memPtr16, I_MAP_VXIDEV, 0,
1);

/* Close instrument session */
iclose(id);
}

Using VXI-Specific Interrupts

Sample: VXI Interrupt Actions (C)

This pseudo-code describes the actions performed by SICL when a VME interrupt arrives and/or a VXI signal register write occurs.

VME Interrupt arrives:
get iack value

send I_INTR_VME_IRQ?

is VME IRQ line configured VME only

if yes then
exit
do lower 8 bits match logical address of one of our servants?
if yes then
/* iack is from one of our servants */
call servant_signal_processing(iack)
else
/* iack is from non-servant VXI or VME device*/
send I_INTR_VXI_VME interrupt to interface
sessions

Signal Register Write occurs:
get value written to signal register
send I_INTR_ANY_SIG
do lower 8 bits match logical address of one of our servants?
if yes then
/* Signal is from one of our servants */
call Servant_signal_processing(value)
else
/* Stray signal */
send I_INTR_VXI_UKNSIG to interface sessions
servant_signal_processing (signal_value)
/* Value is form one of our servants */
is signal value a response signal?
If yes then
process response signal
exit
/* Signal is an event signal */
is signal an RT or RF event?
if yes then
/* A request TRUE or request FALSE arrived */
process request TRUE or request FALSE event
generate SRQ if appropriate
exit
is signal an undefined command event?
if yes then
/* Undefined command event */
process an undefined command event
exit
/* Signal is a user-defined or undefined event */
send I_INTR_VXI_SIGNAL to device sessions for this device
exit

Sample: Processing VME Interrupts (C)

/* vmeintr.c
This example uses SICL to cause a VME interrupt from an E1361 register-based relay card at logical address 136.*/

#include <sicl.h>

static void vmeint (INST, unsigned short);
static void int_setup (INST, unsigned long);
static void int_hndlr (INST, long, long);
int intr = 0;
main() {
int o; INST id_intf1;
unsigned long mask = 1;

ionerror (I_ERROR_EXIT);
iintroff ();
id_intf1 = iopen (“vxi,136”);
int_setup (id_intf1, mask);
vmeint (id_intf1, 136);
/* wait for SRQ or interrupt condition */
iwaithdlr (0);

iintron ();
iclose (id_intf1);
}
static void int_setup(INST id, unsigned long
mask) {
ionintr(id, int_hndlr);
isetintr(id, I_INTR_VXI_SIGNAL, mask);
}
static void vmeint (INST id, unsigned short
laddr) {
int reg;
char *a16_ptr = 0;

reg = 8;
a16_ptr = imap (id, I_MAP_A16, 0, 1, 0);

/* Cause uhf mux to interrupt: */
iwpoke ((unsigned short *)(a16_ptr + 0xc000 +
laddr * 64 + reg), 0x0);
}
static void int_hndlr (INST id, long reason,
long sec) {
printf (“VME interrupt: reason: 0x%x, sec:
0x%x\n”, reason,sec);
intr = 1;
}