/********************************************************************
Name: DRS.cpp
Created by: Stefan Ritt, Matthias Schneebeli
Contents: Library functions for DRS mezzanine and USB boards
$Id: DRS.cpp 13351 2009-04-28 11:12:54Z ritt@PSI.CH $
\********************************************************************/
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <algorithm>
#include <sys/stat.h>
#include "strlcpy.h"
#ifdef _MSC_VER
#pragma warning(disable:4996)
# include <windows.h>
# include <direct.h>
#else
# include <unistd.h>
# include <sys/time.h>
inline void Sleep(useconds_t x)
{
usleep(x * 1000);
}
#endif
#ifdef _MSC_VER
#include <conio.h>
#define drs_kbhit() kbhit()
#else
#include <sys/ioctl.h>
int drs_kbhit()
{
int n;
ioctl(0, FIONREAD, &n);
return (n > 0);
}
static inline int getch()
{
return getchar();
}
#endif
#include <DRS.h>
#ifdef _MSC_VER
extern "C" {
#endif
#include <mxml.h>
#ifdef _MSC_VER
}
#endif
/*---- minimal FPGA firmvare version required for this library -----*/
const int REQUIRED_FIRMWARE_VERSION_DRS2 = 5268;
const int REQUIRED_FIRMWARE_VERSION_DRS3 = 6981;
const int REQUIRED_FIRMWARE_VERSION_DRS4 = 13191;
/*---- VME addresses -----------------------------------------------*/
#ifdef HAVE_VME
/* assuming following DIP Switch settings:
SW1-1: 1 (off) use geographical addressing (1=left, 21=right)
SW1-2: 1 (off) \
SW1-3: 1 (off) > VME_WINSIZE = 8MB, subwindow = 1MB
SW1-4: 0 (on) /
SW1-5: 0 (on) reserverd
SW1-6: 0 (on) reserverd
SW1-7: 0 (on) reserverd
SW1-8: 0 (on) \
|
SW2-1: 0 (on) |
SW2-2: 0 (on) |
SW2-3: 0 (on) |
SW2-4: 0 (on) > VME_ADDR_OFFSET = 0
SW2-5: 0 (on) |
SW2-6: 0 (on) |
SW2-7: 0 (on) |
SW2-8: 0 (on) /
which gives
VME base address = SlotNo * VME_WINSIZE + VME_ADDR_OFFSET
= SlotNo * 0x80'0000
*/
#define GEVPC_BASE_ADDR 0x00000000
#define GEVPC_WINSIZE 0x800000
#define GEVPC_USER_FPGA (GEVPC_WINSIZE*2/8)
#define PMC1_OFFSET 0x00000
#define PMC2_OFFSET 0x80000
#define PMC_CTRL_OFFSET 0x00000 /* all registers 32 bit */
#define PMC_STATUS_OFFSET 0x10000
#define PMC_FIFO_OFFSET 0x20000
#define PMC_RAM_OFFSET 0x40000
#endif // HAVE_VME
/*---- USB addresses -----------------------------------------------*/
#define USB_TIMEOUT 1000 // one second
#ifdef HAVE_USB
#define USB_CTRL_OFFSET 0x00 /* all registers 32 bit */
#define USB_STATUS_OFFSET 0x40
#define USB_RAM_OFFSET 0x80
#define USB_CMD_IDENT 0 // Query identification
#define USB_CMD_ADDR 1 // Address cycle
#define USB_CMD_READ 2 // "VME" read <addr><size>
#define USB_CMD_WRITE 3 // "VME" write <addr><size>
#define USB_CMD_READ12 4 // 12-bit read <LSB><MSB>
#define USB_CMD_WRITE12 5 // 12-bit write <LSB><MSB>
#define USB2_CMD_READ 1
#define USB2_CMD_WRITE 2
#define USB2_CTRL_OFFSET 0x00000 /* all registers 32 bit */
#define USB2_STATUS_OFFSET 0x10000
#define USB2_FIFO_OFFSET 0x20000
#define USB2_RAM_OFFSET 0x40000
#endif // HAVE_USB
/*---- Register addresses ------------------------------------------*/
#ifndef T_CTRL
#define T_CTRL 1
#define T_STATUS 2
#define T_RAM 3
#define T_FIFO 4
#endif
#define REG_CTRL 0x00000 /* 32 bit control reg */
#define REG_DAC_OFS 0x00004
#define REG_DAC0 0x00004
#define REG_DAC1 0x00006
#define REG_DAC2 0x00008
#define REG_DAC3 0x0000A
#define REG_DAC4 0x0000C
#define REG_DAC5 0x0000E
#define REG_DAC6 0x00010
#define REG_DAC7 0x00012
#define REG_CHANNEL_CONFIG 0x00014 // low byte
#define REG_CONFIG 0x00014 // high byte
#define REG_CHANNEL_SPAN 0x00016
#define REG_FREQ_SET_HI 0x00018 // DRS2
#define REG_FREQ_SET_LO 0x0001A // DRS2
#define REG_TRG_DELAY 0x00018 // DRS4
#define REG_FREQ_SET 0x0001A // DRS4
#define REG_TRIG_DELAY 0x0001C
#define REG_LMK_MSB 0x0001C // DRS4 Mezz
#define REG_CALIB_TIMING 0x0001E // DRS2
#define REG_EEPROM_PAGE 0x0001E // DRS4
#define REG_LMK_LSB 0x0001E // DRS4 Mezz
#define REG_MAGIC 0x00000
#define REG_BOARD_TYPE 0x00002
#define REG_STATUS 0x00004
#define REG_RDAC_OFS 0x0000E
#define REG_RDAC0 0x00008
#define REG_STOP_CELL0 0x00008
#define REG_RDAC1 0x0000A
#define REG_STOP_CELL1 0x0000A
#define REG_RDAC2 0x0000C
#define REG_STOP_CELL2 0x0000C
#define REG_RDAC3 0x0000E
#define REG_STOP_CELL3 0x0000E
#define REG_RDAC4 0x00000
#define REG_RDAC5 0x00002
#define REG_RDAC6 0x00014
#define REG_RDAC7 0x00016
#define REG_EVENTS_IN_FIFO 0x00018
#define REG_EVENT_COUNT 0x0001A
#define REG_FREQ1 0x0001C
#define REG_FREQ2 0x0001E
#define REG_TEMPERATURE 0x00020
#define REG_TRIGGER_BUS 0x00022
#define REG_SERIAL_BOARD 0x00024
#define REG_VERSION_FW 0x00026
/*------------------------------------------------------------------*/
using namespace std;
#ifdef HAVE_USB
#define USB2_BUFFER_SIZE (1024*1024+10)
unsigned char static *usb2_buffer = NULL;
#endif
/*------------------------------------------------------------------*/
DRS::DRS()
: fNumberOfBoards(0)
#ifdef HAVE_VME
, fVmeInterface(0)
#endif
{
#ifdef HAVE_USB
MUSB_INTERFACE *usb_interface;
#endif
#if defined(HAVE_VME) || defined(HAVE_USB)
int index = 0, i = 0;
#endif
memset(fError, 0, sizeof(fError));
#ifdef HAVE_VME
unsigned short type, fw, magic, serial, temperature;
mvme_addr_t addr;
if (mvme_open(&fVmeInterface, 0) == MVME_SUCCESS) {
mvme_set_am(fVmeInterface, MVME_AM_A32);
mvme_set_dmode(fVmeInterface, MVME_DMODE_D16);
/* check all VME slave slots */
for (index = 2; index <= 21; index++) {
/* check PMC1 */
addr = GEVPC_BASE_ADDR + index * GEVPC_WINSIZE; // VME board base address
addr += GEVPC_USER_FPGA; // UsrFPGA base address
addr += PMC1_OFFSET; // PMC1 offset
mvme_set_dmode(fVmeInterface, MVME_DMODE_D16);
i = mvme_read(fVmeInterface, &magic, addr + PMC_STATUS_OFFSET + REG_MAGIC, 2);
if (i == 2) {
if (magic != 0xC0DE) {
printf("Found old firmware, please upgrade immediately!\n");
fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, (index - 2) << 1);
fNumberOfBoards++;
} else {
/* read board type */
mvme_read(fVmeInterface, &type, addr + PMC_STATUS_OFFSET + REG_BOARD_TYPE, 2);
type &= 0xFF;
if (type == 2 || type == 3 || type == 4) { // DRS2 or DRS3 or DRS4
/* read firmware number */
mvme_read(fVmeInterface, &fw, addr + PMC_STATUS_OFFSET + REG_VERSION_FW, 2);
/* read serial number */
mvme_read(fVmeInterface, &serial, addr + PMC_STATUS_OFFSET + REG_SERIAL_BOARD, 2);
/* read temperature register to see if CMC card is present */
mvme_read(fVmeInterface, &temperature, addr + PMC_STATUS_OFFSET + REG_TEMPERATURE, 2);
/* LED blinking */
#if 0
do {
data = 0x00040000;
mvme_write(fVmeInterface, addr + PMC_CTRL_OFFSET + REG_CTRL, &data, sizeof(data));
mvme_write(fVmeInterface, addr + PMC2_OFFSET + PMC_CTRL_OFFSET + REG_CTRL, &data,
sizeof(data));
Sleep(500);
data = 0x00000000;
mvme_write(fVmeInterface, addr + PMC_CTRL_OFFSET + REG_CTRL, &data, sizeof(data));
mvme_write(fVmeInterface, addr + PMC2_OFFSET + PMC_CTRL_OFFSET + REG_CTRL, data,
sizeof(data));
Sleep(500);
} while (1);
#endif
if (temperature == 0xFFFF) {
//printf("slot %d, fw %d, no CMC board in upper slot\n", index, fw);
} else {
//printf("slot %d, fw %d, CMC serial %d in upper slot\n", index, fw, serial);
fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, (index - 2) << 1);
if (fBoard[fNumberOfBoards]->HasCorrectFirmware())
fNumberOfBoards++;
else
sprintf(fError, "Wrong firmware version: board has %d, required is %d\n",
fBoard[fNumberOfBoards]->GetFirmwareVersion(),
fBoard[fNumberOfBoards]->GetRequiredFirmwareVersion());
}
}
}
}
/* check PMC2 */
addr = GEVPC_BASE_ADDR + index * GEVPC_WINSIZE; // VME board base address
addr += GEVPC_USER_FPGA; // UsrFPGA base address
addr += PMC2_OFFSET; // PMC2 offset
mvme_set_dmode(fVmeInterface, MVME_DMODE_D16);
i = mvme_read(fVmeInterface, &fw, addr + PMC_STATUS_OFFSET + REG_MAGIC, 2);
if (i == 2) {
if (magic != 0xC0DE) {
printf("Found old firmware, please upgrade immediately!\n");
fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, (index - 2) << 1 | 1);
fNumberOfBoards++;
} else {
... 5173 more lines ...
|
/********************************************************************
DRS.h, S.Ritt, M. Schneebeli - PSI
$Id: DRS.h 13347 2009-04-28 08:24:05Z ritt@PSI.CH $
********************************************************************/
#ifndef DRS_H
#define DRS_H
#include <stdio.h>
#include <string.h>
#ifdef HAVE_LIBUSB
# ifndef HAVE_USB
# define HAVE_USB
# endif
#endif
#ifdef HAVE_USB
# include <musbstd.h>
#endif // HAVE_USB
#ifdef HAVE_VME
# include <mvmestd.h>
#endif // HAVE_VME
/* disable "deprecated" warning */
#ifdef _MSC_VER
#pragma warning(disable: 4996)
#endif
#ifndef NULL
#define NULL 0
#endif
/* transport mode */
#define TR_VME 1
#define TR_USB 2
#define TR_USB2 3
/* address types */
#define T_CTRL 1
#define T_STATUS 2
#define T_RAM 3
#define T_FIFO 4
/* control register bit definitions */
#define BIT_START_TRIG (1<<0) // write a "1" to start domino wave
#define BIT_REINIT_TRIG (1<<1) // write a "1" to stop & reset DRS
#define BIT_SOFT_TRIG (1<<2) // write a "1" to stop and read data to RAM
#define BIT_EEPROM_WRITE_TRIG (1<<3) // write a "1" to write into serial EEPROM
#define BIT_EEPROM_READ_TRIG (1<<4) // write a "1" to read from serial EEPROM
#define BIT_AUTOSTART (1<<16)
#define BIT_DMODE (1<<17) // (*DRS2*) 0: single shot, 1: circular
#define BIT_LED (1<<18) // 1=on, 0=blink during readout
#define BIT_TCAL_EN (1<<19) // switch on (1) / off (0) for 33 MHz calib signal
#define BIT_TCAL_SOURCE (1<<20)
#define BIT_REFCLK_SOURCE (1<<20)
#define BIT_FREQ_AUTO_ADJ (1<<21) // DRS2/3
#define BIT_TRANSP_MODE (1<<21) // DRS4
#define BIT_ENABLE_TRIGGER1 (1<<22) // External LEMO/FP/TRBUS trigger
#define BIT_LONG_START_PULSE (1<<23) // (*DRS2*) 0:short start pulse (>0.8GHz), 1:long start pulse (<0.8GHz)
#define BIT_READOUT_MODE (1<<23) // (*DRS3*) 0:start from first bin, 1:start from domino stop
#define BIT_DELAYED_START (1<<24) // DRS2: start domino wave 400ns after soft trigger, used for waveform
// generator startup
#define BIT_NEG_TRIGGER (1<<24) // DRS4: use high-to-low trigger if set
#define BIT_ACAL_EN (1<<25) // connect DRS to inputs (0) or to DAC6 (1)
#define BIT_TRIGGER_DELAYED (1<<26) // select delayed trigger from trigger bus
#define BIT_DACTIVE (1<<27) // keep domino wave running during readout
#define BIT_STANDBY_MODE (1<<28) // put chip in standby mode
#define BIT_TR_SOURCE1 (1<<29) // trigger source selection bits
#define BIT_TR_SOURCE2 (1<<30) // trigger source selection bits
#define BIT_ENABLE_TRIGGER2 (1<<31) // analog threshold (internal) trigger
/* status register bit definitions */
#define BIT_RUNNING (1<<0) // one if domino wave running or readout in progress
#define BIT_NEW_FREQ1 (1<<1) // one if new frequency measurement available
#define BIT_NEW_FREQ2 (1<<2)
#define BIT_PLL_LOCKED0 (1<<1) // 1 if PLL has locked (DRS4 evaluation board only)
#define BIT_PLL_LOCKED1 (1<<2) // 1 if PLL DRS4 B has locked (DRS4 mezzanine board only)
#define BIT_PLL_LOCKED2 (1<<3) // 1 if PLL DRS4 C has locked (DRS4 mezzanine board only)
#define BIT_PLL_LOCKED3 (1<<4) // 1 if PLL DRS4 D has locked (DRS4 mezzanine board only)
#define BIT_EEPROM_BUSY (1<<5) // 1 if EEPROM operation in progress
/* configuration register bit definitions */
#define BIT_CONFIG_DMODE (1<<8) // 0: single shot, 1: circular
#define BIT_CONFIG_PLLEN (1<<9) // write a "1" to enable the internal PLL
#define BIT_CONFIG_WSRLOOP (1<<10) // write a "1" to connect WSROUT to WSRIN internally
enum DRSBoardConstants {
kNumberOfChannelsV2 = 10,
kNumberOfChannelsV4 = 9,
kNumberOfCalibChannelsV3 = 10,
kNumberOfCalibChannelsV4 = 9,
kNumberOfBins = 1024,
kNumberOfChips = 2,
kFrequencyCacheSize = 10,
kBSplineOrder = 4,
kPreCaliculatedBSplines = 1000,
kPreCaliculatedBSplineGroups = 5,
kNumberOfADCBins = 4096,
kBSplineXMinOffset = 20,
kMaxNumberOfClockCycles = 100,
};
enum DRSErrorCodes {
kSuccess = 0,
kInvalidTriggerSignal = -1,
kWrongChannelOrChip = -2,
kInvalidTransport = -3,
kZeroSuppression = -4,
kWaveNotAvailable = -5
};
/*---- callback class ----*/
class DRSCallback
{
public:
virtual void Progress(int value) = 0;
virtual ~DRSCallback() {};
};
/*------------------------*/
class DRSBoard;
class ResponseCalibration {
protected:
class CalibrationData {
public:
class CalibrationDataChannel {
public:
unsigned char fLimitGroup[kNumberOfBins]; //!
float fMin[kNumberOfBins]; //!
float fRange[kNumberOfBins]; //!
short fOffset[kNumberOfBins]; //!
short fGain[kNumberOfBins]; //!
unsigned short fOffsetADC[kNumberOfBins]; //!
short *fData[kNumberOfBins]; //!
unsigned char *fLookUp[kNumberOfBins]; //!
unsigned short fLookUpOffset[kNumberOfBins]; //!
unsigned char fNumberOfLookUpPoints[kNumberOfBins]; //!
float *fTempData; //!
private:
CalibrationDataChannel(const CalibrationDataChannel &c); // not implemented
CalibrationDataChannel &operator=(const CalibrationDataChannel &rhs); // not implemented
public:
CalibrationDataChannel(int numberOfGridPoints)
:fTempData(new float[numberOfGridPoints]) {
int i;
for (i = 0; i < kNumberOfBins; i++) {
fData[i] = new short[numberOfGridPoints];
}
memset(fLimitGroup, 0, sizeof(fLimitGroup));
memset(fMin, 0, sizeof(fMin));
memset(fRange, 0, sizeof(fRange));
memset(fOffset, 0, sizeof(fOffset));
memset(fGain, 0, sizeof(fGain));
memset(fOffsetADC, 0, sizeof(fOffsetADC));
memset(fLookUp, 0, sizeof(fLookUp));
memset(fLookUpOffset, 0, sizeof(fLookUpOffset));
memset(fNumberOfLookUpPoints, 0, sizeof(fNumberOfLookUpPoints));
}
~CalibrationDataChannel() {
int i;
delete fTempData;
for (i = 0; i < kNumberOfBins; i++) {
delete fData[i];
delete fLookUp[i];
}
}
};
bool fRead; //!
CalibrationDataChannel *fChannel[10]; //!
unsigned char fNumberOfGridPoints; //!
int fHasOffsetCalibration; //!
float fStartTemperature; //!
float fEndTemperature; //!
int *fBSplineOffsetLookUp[kNumberOfADCBins]; //!
float **fBSplineLookUp[kNumberOfADCBins]; //!
float fMin; //!
float fMax; //!
unsigned char fNumberOfLimitGroups; //!
static float fIntRevers[2 * kBSplineOrder - 2];
private:
CalibrationData(const CalibrationData &c); // not implemented
CalibrationData &operator=(const CalibrationData &rhs); // not implemented
public:
CalibrationData(int numberOfGridPoints);
~CalibrationData();
static int CalculateBSpline(int nGrid, float value, float *bsplines);
void PreCalculateBSpline();
void DeletePreCalculatedBSpline();
};
// General Fields
DRSBoard *fBoard;
double fPrecision;
// Fields for creating the Calibration
bool fInitialized;
bool fRecorded;
bool fFitted;
bool fOffset;
bool fCalibrationValid[2];
int fNumberOfPointsLowVolt;
int fNumberOfPoints;
int fNumberOfMode2Bins;
int fNumberOfSamples;
int fNumberOfGridPoints;
int fNumberOfXConstPoints;
int fNumberOfXConstGridPoints;
double fTriggerFrequency;
int fShowStatistics;
FILE *fCalibFile;
int fCurrentLowVoltPoint;
int fCurrentPoint;
int fCurrentSample;
int fCurrentFitChannel;
int fCurrentFitBin;
float *fResponseX[10][kNumberOfBins];
float *fResponseY;
unsigned short **fWaveFormMode3[10];
unsigned short **fWaveFormMode2[10];
unsigned short **fWaveFormOffset[10];
unsigned short **fWaveFormOffsetADC[10];
unsigned short *fSamples;
int *fSampleUsed;
float *fPntX[2];
float *fPntY[2];
float *fUValues[2];
float *fRes[kNumberOfBins];
float *fResX[kNumberOfBins];
double *fXXFit;
double *fYYFit;
double *fWWFit;
double *fYYFitRes;
double *fYYSave;
double *fXXSave;
double fGainMin;
double fGainMax;
float **fStatisticsApprox;
float **fStatisticsApproxExt;
// Fields for applying the Calibration
CalibrationData *fCalibrationData[kNumberOfChips];
private:
ResponseCalibration(const ResponseCalibration &c); // not implemented
ResponseCalibration &operator=(const ResponseCalibration &rhs); // not implemented
public:
ResponseCalibration(DRSBoard* board);
~ResponseCalibration();
void SetCalibrationParameters(int numberOfPointsLowVolt, int numberOfPoints, int numberOfMode2Bins,
int numberOfSamples, int numberOfGridPoints, int numberOfXConstPoints,
int numberOfXConstGridPoints, double triggerFrequency, int showStatistics = 0);
void ResetCalibration();
bool RecordCalibrationPoints(int chipNumber);
bool RecordCalibrationPointsV3(int chipNumber);
bool RecordCalibrationPointsV4(int chipNumber);
bool FitCalibrationPoints(int chipNumber);
bool FitCalibrationPointsV3(int chipNumber);
bool FitCalibrationPointsV4(int chipNumber);
bool OffsetCalibration(int chipNumber);
bool OffsetCalibrationV3(int chipNumber);
bool OffsetCalibrationV4(int chipNumber);
double GetTemperature(unsigned int chipIndex);
bool WriteCalibration(unsigned int chipIndex);
bool WriteCalibrationV3(unsigned int chipIndex);
bool WriteCalibrationV4(unsigned int chipIndex);
bool ReadCalibration(unsigned int chipIndex);
bool ReadCalibrationV3(unsigned int chipIndex);
bool ReadCalibrationV4(unsigned int chipIndex);
bool Calibrate(unsigned int chipIndex, unsigned int channel, float *adcWaveform,
float *uWaveform, float threshold, bool offsetCalib);
bool Calibrate(unsigned int chipIndex, unsigned int channel, unsigned short *adcWaveform, unsigned short *uWaveform,
int triggerCell, float threshold, bool offsetCalib);
bool SubtractADCOffset(unsigned int chipIndex, unsigned int channel, unsigned short *adcWaveform,
unsigned short *adcCalibratedWaveform, unsigned short newBaseLevel);
bool IsRead(int chipIndex) const { return fCalibrationValid[chipIndex]; }
double GetPrecision() const { return fPrecision; };
double GetOffsetAt(int chip,int chn,int bin) const { return fCalibrationData[chip]->fChannel[chn]->fOffset[bin]; };
double GetGainAt(int chip,int chn,int bin) const { return fCalibrationData[chip]->fChannel[chn]->fGain[bin]; };
... 336 more lines ...
|