devLib2  2.12
VME64 CSR Usage

When working with a CSR/CR device the first step is to find the identifiers for the board. This should be included in vendor documentation, and can be verified by probing the appropriate VME slot at runtime. The library functions vmecsrdump(lvl) and vmecsrprint(slot,lvl) can be used for this. See the IOC shell section for detail on these functions.

Including this identifying information in your code provides an important safe guard against user mis-configuration. This provides an easy way to prevent your code from trying to access the wrong type of device.

To initialize you must know its slot number. While it is possible to automatically detect cards it is preferable to have a user defined mapping between physical id (slot#) and logical id (Asyn port, device ID, etc.). This allows for consistent naming even if cards are added or removed from the system.

For EPICS drivers initialization will usually be done with an IOC shell function. For example:

myVMECardSetup("dac", 5, 0x210000, 4, 0x60)

Would set card "dac" to be the card in slot 5. This imaginary card is given an A24 base address of 0x210000, and set to generate interrupt vector 0x60 at level 4.

Below is an example implementation of myVMECardSetup().

static const struct VMECSRID mydevids[] = {...}
int
myVMECardSetup(const char* port,
int slot,
unsigned long base,
int level,
int vector)
{
volatile void* csr, a24;
devpriv *priv;
if( portExists(port) ) return 1;
csr=devCSRTestSlot(mydevids, slot, NULL);
if (!csr) return 2;

The first step is to probe the VME slot and get the CSR base address. If the slot were empty or populated with an unsupported card then we would abort here.

#if card is VME64
CSRWrite24(csr + MYCSR_BAR_BASE, base);
#elif card is VME64x
#endif

Assuming the card supports full jumperless configuration then then base address will be programmed using the CSR space. While newer VME64x cards have standard base address registers for this, older VME64 cards do not. For these card the vendor should document the correct way to set the base address.

if (devRegisterAddress("mydrv", atVMEA24, base, 0xff, &a24))
return 3;

Once the A24 base address is set we map it into the process' address space with the standard devLib mapping call.

priv=calloc(1, sizeof(mydevpriv));
if (!priv) return 4;
if (devConnectInterruptVME(vector&0xff, &myisr, priv))
return 5;
if (devEnableInterruptLevelVME(level&0x7)) return 6;

Always attach the interrupt handler before enabling interrupts.

CSRWrite8(csr + MYCSR_IRQ_LEVEL, level&0x7);
CSRWrite8(csr + MYCSR_IRQ_VECTOR, vector&0xff);

Neither VME64 or VME64x specifies standard registers for interrupt level or vector code. Vendor documention must specify how to set this.

.Note

This may not be done in the CSR space, but rather in another address space.

portCreate(port, priv);
return 0;
}