Accessing VME devices from Readout code

(Ron Fox ( Last modified 7/29/2004 4:19 PM).

While the NSCL data acquisition system supports a large set of VME electronics, it may be necessary for the user to control some custom VME electronics that is not included in this set. This Application Note:

·        Will provide an overview of the VME bus.

·        Describes the low level interfaces to the VME bus.

·        Describes an object oriented interface to the VME bus that is also available.


An overview of the VME bus

The VME bus is originally a computer bus, not an instrumentation bus.  The bus can be thought of as composed of memory that is accessed by your application.  In fact, some memory cells will correspond to device registers and manipulating those device registers will cause changes in the device.


A cycle on the VME bus consists of an address cycle that establishes which device is being accessed, and a data cycle that transfers data either from or to the device from the host computer.  The VME address cycle, in addition to presenting the bus with an address, also presents an address space identifier called an “address modifier” (usually abbreviated AM).  In theory, a VME device need only respond to specific combinations of address modifiers and addresses.  This means that the address modifier selects an address space, and the address a location within that address space.


Many AM’s have established meanings.  The primary AM’s that you will deal with are (symbolically):





16 bits of significant address.  Usually simple I/O cards present themselves in A16 space.


24 bits of significant address.  This is the original VME specification.  A24 space provides 16Mbytes of address space.


32 bits of significant address.  This is an extension to the original specification that most systems (including ours at the NSCL) support.


Devices also accept specific data transfer widths.  There are two ways to describe these widths:



Computer style




8 bits of data are transferred



16 bits of data are transferred



32 bits of data are transferred


VME bus card specifications often describe the access capabilities of the card in terms of the address space and data transfer width the device can accept.  For example an A32D16 device lives in A32 address space, but can only accept 16 bit transfers.


The VME busses used at the NSCL include a CERN designed extension to the VME bus addressing capabilities that are supported by some devices.  The middle backplane connector contains an encoding of the slot.  Some devices can compute a base address in one of the address spaces based on the value presented in this slot encoding.  When accessed via this base address and the address modifier that decodes this, we refer to the module as being geographically addressed.  The intent of this extension is to mimic the slot addressable capability of older instrumentation busses like CAMAC.


Low level interfaces to the VME bus


The low level interfaces to the VME bus are shown in the figure below.  Regardless of the interface type, this “software stack” exists if the interface is supported:




At the lowest level is the kernel module that is the device driver for the VME bus interface.  This driver can be controlled via system service calls such as read(2), write(2), mmap(2) and ioctl(2).

·        Above that the vendor usually supplies a library that bundles the system service calls into sensible combinations.  For example, in order to do a read from the device it may be necessary to seek the address, do an ioctl to establish the address modifier and then do a read.  These can be bundled into a single library call like readvme().

·        If all of the electronic module support was programmed against either of the bottom two layers of the VME support stack, it would be necessary to rewrite module support for each type of VME bus interface. We therefore provide an interface layer that allows you to perform most of the operations you will need to do to the VME bus (read, write, and map address segments if that is supported by the interface) in a portable manner.  This is the purpose of the Device independent abstraction layer”

·        Some device interfaces support special device specific functions.  For example the SBS/Bit3 interface used at the NSCL supports DMA throttling.  A device dependent abstraction layer provides a similar set of interfaces that are marked as device specific so that you will  know if you are writing code that may be non portable.


You should program to the top layers of this stack unless you have a really good reason not to.  The higher layers are easier to deal with and make your code maximally portable to other interfaces we support and may support in the future.


Device Independent Abstraction Layer

The device independent abstraction layer code is defined in the header CVMEInterface.h.  Code that uses this software must link to the VmeAPI library (e.g. –lVmeAPI on the link command).  CVMEInterface supports the following operations as static members of a class called CVMEInterface:







Opens a channel to the VME bus using a specified address modifier.  The address modifiers are defined symbolically as members of the CVMEInterace class.  For example, the A24 space can be accessed by opening with the address modifier CVMEInterface::A24



Closes a previously open channel to the VME.  Note that close does not invalidate any existing memory maps, however those memory maps cannot be released until program exit.

Map memory


Map a region of VME address space into process memory.  This function returns a pointer that, when dereferenced transfers data to or from the chunk of VME space that is mapped.

Unmap memory


Remove a chunk of VME address space from the process adress space.

Block Read


Performs a block read from the VME space

Block Write


Performs a block write to the VME space.

Lock the VME


Obtain advisory exclusive access to the VME buses. VME interfaces may not allow simultaneous block transfers and single shot (mapped) transfers.  Locks are released via Unlock or process exit.  If you attempt to lock the VME while you are already holding the lock you will deadlock.

Unlock the VME


Release an advisory lock obtained via Lock.



The following sample code opens the VME bus for A24 space and creates a 256byte map starting at base address 0x400000. The map is then released:

#include <CVMEInterface.h>
void* pVme;
// Access the vme bus:
  pVme = CVMEInterface::Open(CVMEInterface::A24); // Crate 0 by default.
  void* pSpace = CVMEInterface::Map(pVme, 0x400000, 256);
  // Do stuff to the VME space:
  // Release the map and close the device:
  CVMEInterface::Unmap(pVme, pSpace, 256);


Device Dependent Abstraction Layer.

Some VME interfaces have special functions that are specific to the device itself.  When the DAQ system is built, a specific interface type is specified.  The device dependent and independent abstraction software for the VME interface specified are then built into the VmeAPI library described in the previous section.  The device dependent layer is a static class whose name will vary from interface type to interface type.  For the interfaces used at the NSCL (SBS/Bit3), the class is called CSBSBit3VmeInterface and is described in the header file SBSBit3API.h   The code below is SBS/Bit3 specific and shows how to do a VME bus reset:


#include <CVMEInterface.h>
#include <SBSBit3API.h>
void* pVme;
  // access the vme bus.
  pVme = CVMEInterface::Open(CVMEInterface::A24); // Crate 0 by default.
 // reset the bus:


Object oriented interfaces to the VME bus.

Above the abstraction layers is an object oriented interface (CVmeModule) to the VME bus.  Using this interface is a bit clumsier than using the abstraction layers, however CVmeModule is knows something about the capabilities of the device and adjusts its behavior accordingly.   For example, not all VME interfaces support memory mapping.  If available, memory mapped windows are the quickest way to do single shot operations to the VME since there is no per operation driver overhead.  If the interface does not support memory mapping, CVmeModule will fall back to using the Read/Write capability of the module even for single shot operations.  CVmeModule is defined in VmeModule.h  The implementation of the class is in libDeviceSupport  (add –lDeviceSupport to your application link line if it is not already there).

Use CVmeModule as follows:

·        Construct an object of type CVmeModule that represents the slice of VME address space you wish to access.

·        Use the peek* and poke* member functions to access the VME address space represented by the object

·        When you are done, destroy the object.


The code fragment below shows you how to create a CVmeModule object that represents a chunk of  A24 space based at 0x400000, extends for 256 bytes.  The second longword of that space is read (offset 4), and the fourth word (offset 6) is written.

#include <VmeModule.h>
   CVmeModule module(CVmeModule::a24d32, 0x400000, 256); 
   module.pokel(0x1234678, 1);        // longword 1 numbered from 0.
   unsigned short value = module.peekw(3); // word 4 counting from 0.