New device support for the Pentek 4261 ADC.
This commit is contained in:
758
src/dev/devWfPentek4261.c
Normal file
758
src/dev/devWfPentek4261.c
Normal file
@@ -0,0 +1,758 @@
|
||||
|
||||
/*
|
||||
*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE,
|
||||
AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE
|
||||
AND IN ALL SOURCE LISTINGS OF THE CODE.
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
Argonne National Laboratory (ANL), with facilities in the States of
|
||||
Illinois and Idaho, is owned by the United States Government, and
|
||||
operated by the University of Chicago under provision of a contract
|
||||
with the Department of Energy.
|
||||
|
||||
Portions of this material resulted from work developed under a U.S.
|
||||
Government contract and are subject to the following license: For
|
||||
a period of five years from March 30, 1993, the Government is
|
||||
granted for itself and others acting on its behalf a paid-up,
|
||||
nonexclusive, irrevocable worldwide license in this computer
|
||||
software to reproduce, prepare derivative works, and perform
|
||||
publicly and display publicly. With the approval of DOE, this
|
||||
period may be renewed for two additional five year periods.
|
||||
Following the expiration of this period or periods, the Government
|
||||
is granted for itself and others acting on its behalf, a paid-up,
|
||||
nonexclusive, irrevocable worldwide license in this computer
|
||||
software to reproduce, prepare derivative works, distribute copies
|
||||
to the public, perform publicly and display publicly, and to permit
|
||||
others to do so.
|
||||
|
||||
*****************************************************************
|
||||
DISCLAIMER
|
||||
*****************************************************************
|
||||
|
||||
NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR
|
||||
THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS,
|
||||
MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL
|
||||
LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
|
||||
USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS
|
||||
DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY
|
||||
OWNED RIGHTS.
|
||||
|
||||
*****************************************************************
|
||||
LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY
|
||||
DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000).
|
||||
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <vme.h>
|
||||
#include <iv.h>
|
||||
#include <vxLib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <intLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <module_types.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <dbDefs.h>
|
||||
#include <recSup.h>
|
||||
#include <devSup.h>
|
||||
#include <dbScan.h>
|
||||
#include <callback.h>
|
||||
#include <waveformRecord.h>
|
||||
|
||||
/*
|
||||
This is waveform record support for the Pentek 4261A 10MHz 12 bit ADC.
|
||||
All scan types are supported, including I/O interrupt scan. The ADC
|
||||
currently supports the edge trigger mode for starting the sampling
|
||||
operation. The ADC is programmed to record an array of samples the
|
||||
same size as the waveform record. The internal or an external clock
|
||||
may be used as the sampling clock. The sampling can be triggered by
|
||||
an external signal, or automatically by record support.
|
||||
|
||||
Using I/O interrupt scanning, the record is processed and the waveform
|
||||
record array is updated each time an external trigger signal is present.
|
||||
With the other scan types, the waveform array is updated each time the
|
||||
record is processed.
|
||||
|
||||
I could not get the continuous bank swapping feature to work with the
|
||||
trigger, I got a glitch in the data approximately 1 us into the sampling.
|
||||
After each round of sampling is done, the buffers are reset.
|
||||
|
||||
The function ConfigurePentekADC() must be run in the
|
||||
vxWorks startup.cmd file for every ADC board present. This function
|
||||
makes it easy to configure jumpers on the ADC and inform EPICS of them.
|
||||
|
||||
parameters:
|
||||
|
||||
ConfigurePentekADC(
|
||||
int card, - the ADC card number in the crate (0=first)
|
||||
unsigned long a16_base, - where the card exists in A16
|
||||
unsigned long a32_base, - where the card exists in A32 (not used)
|
||||
int irq_vector, - interrupt request vector number
|
||||
int irq_level, - interrupt request level number
|
||||
int word_clock, - the ADC word clock (see 4261 documentation)
|
||||
unsigned long clock_freq - clock frequency (see notes below)
|
||||
)
|
||||
|
||||
Good values to use for configuring the module:
|
||||
A16 base address = 0x0200
|
||||
A32 base address = 0xc0200000 (A32 not used in the support)
|
||||
IRQ vector = 121
|
||||
IRQ level = 3
|
||||
word clock = 32
|
||||
|
||||
The number of samples programed (size of waveform record) must be
|
||||
divisible by the word clock.
|
||||
|
||||
The operating mode the ADC is selected using the input field parm area.
|
||||
The user must supply two option, the clock type and the trigger type,
|
||||
in that order. Here are all the valid parm field entry and what they
|
||||
represent (all are entered as strings without the quotes):
|
||||
|
||||
"x_clock,x_trigger" = external clock and external trigger inputs.
|
||||
"i_clock,x_trigger" = internal clock and external trigger input.
|
||||
"x_clock,i_trigger" = external clock and internal trigger input.
|
||||
"i_clock,i_trigger" = internal clock and internal trigger input.
|
||||
|
||||
If external trigger is selected and scan type is not I/O interrupt scan,
|
||||
then sampling will start on the next external trigger input after device
|
||||
support completes.
|
||||
|
||||
If internal trigger is selected, the sampling will be started by software
|
||||
at the end of device support. Internal trigger only applied to scan
|
||||
types that are not I/O interrupt scanned.
|
||||
|
||||
Configuration function clock frequency note:
|
||||
The clock frequency specified in the configuration function is only
|
||||
applicable to the internal clock. When the external clock is used,
|
||||
the clock frequency parameter is meaningless, the sampling clock
|
||||
will be the external clock frequency. When the internal clock is
|
||||
used (10MHz), the clock frequency parameter will be the sampling
|
||||
frequency. The 10Mhz internal clock must be divisible by the clock
|
||||
frequency value.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Modify devSup.ascii and do a makesdr. Add devPentekADC
|
||||
device support to the waveform record.
|
||||
|
||||
Running ReportPentekADC() will print a report of configuration for
|
||||
the ADC.
|
||||
|
||||
Waveform data types of long, short, unsigned short, double, and float are
|
||||
supported.
|
||||
*/
|
||||
|
||||
long devWfPentek4261Debug=0;
|
||||
|
||||
#define CMD_ADDED 0
|
||||
#define CMD_DELETED 1
|
||||
|
||||
#define A16_SIZE 256
|
||||
#define A32_SIZE 256
|
||||
#define MAX_CARDS 4
|
||||
#define MAX_FILES_ALLOWED 20
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
/* IMPORTANT, LOOK HERE: test areas - good ones to use for jumpers */
|
||||
/* They are good setting for the jumpers for the first ADC card,
|
||||
none of these defines are actually used, are they parameters come
|
||||
from the ConfigurePentekADC().
|
||||
*/
|
||||
|
||||
#define A16_BASE 0xffff0200
|
||||
#define A32_BASE 0xc0200000 /* not really used currently */
|
||||
#define IRQ_VECTOR ((unsigned char)121)
|
||||
#define IRQ_LEVEL 3
|
||||
#define WORD_CLOCK 32 /* my default */
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
#define INTERNAL_CLOCK 10000000 /* 10MHz */
|
||||
|
||||
#define SAMPLE_CLOCK_SELECT 0x08
|
||||
#define EXT_TRIGGER_ENABLE 0x04
|
||||
#define RESET_RUN_FF 0x02
|
||||
#define SET_RUN_FF 0x01
|
||||
|
||||
#define START_MODE 0x20
|
||||
|
||||
#define EXTERNAL 0
|
||||
#define INTERNAL 1
|
||||
|
||||
struct card {
|
||||
int in_use;
|
||||
unsigned long a16_base;
|
||||
unsigned long a32_base;
|
||||
int irq_vector;
|
||||
int irq_level;
|
||||
int word_clock;
|
||||
unsigned long clock_freq;
|
||||
int soc;
|
||||
};
|
||||
typedef struct card CARD;
|
||||
|
||||
/* careful here: horrid looking structure -offset and access (rw=read/write) */
|
||||
struct adc {
|
||||
unsigned short ctc0_bs_a; /* 0x00 rw */
|
||||
unsigned short ctc1_bs_b; /* 0x02 rw */
|
||||
unsigned short ctc2_clock_div; /* 0x04 rw */
|
||||
unsigned short ctc_control; /*c0x06 rw */ /*char a;*/ short junk1[0x04];
|
||||
unsigned short int_id_status; /*c0x10 rw */ /*char b;*/
|
||||
unsigned short int_mask; /*c0x12 rw */ /*char c;*/
|
||||
unsigned short command; /*c0x14 rw */ /*char d;*/
|
||||
unsigned short trigger; /*c0x16 rw */ /*char e;*/
|
||||
unsigned short reserved; /* 0x18 -- */
|
||||
unsigned short tag_cmd; /*c0x1a rw */ /*char f;*/
|
||||
unsigned short tag_data; /* 0x1c rw */
|
||||
unsigned short int_status; /*c0x1e r- */ /*char g;*/ char junk2[0x10];
|
||||
unsigned short vme_fifo; /* 0x30 rw */
|
||||
};
|
||||
typedef struct adc ADC;
|
||||
|
||||
struct pvt_area {
|
||||
CALLBACK callback;
|
||||
int clock_mode;
|
||||
int trigger_mode;
|
||||
int last_int_status;
|
||||
int last_status;
|
||||
volatile ADC* adc_regs;
|
||||
unsigned short div;
|
||||
int card;
|
||||
int file_count;
|
||||
unsigned long total_count;
|
||||
};
|
||||
typedef struct pvt_area PVT_AREA;
|
||||
|
||||
static long dev_report(int level);
|
||||
static long dev_init(int after);
|
||||
static long dev_init_rec(struct waveformRecord* pr);
|
||||
static long dev_ioint_info(int cmd,struct waveformRecord* pr,IOSCANPVT* iopvt);
|
||||
static long dev_read(struct waveformRecord* pr);
|
||||
static long dev_complete_read(struct waveformRecord* pr);
|
||||
static long dev_other_read(struct waveformRecord* pr);
|
||||
static void irq_func(void*);
|
||||
static int full_reset(PVT_AREA* pvt);
|
||||
static int buffer_reset(PVT_AREA* pvt);
|
||||
static long setup(PVT_AREA* pvt);
|
||||
|
||||
void ConfigurePentekADC(int,unsigned long,unsigned long,int,int,int,unsigned long);
|
||||
|
||||
/* generic structure for device support */
|
||||
typedef struct {
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record;
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_write;
|
||||
DEVSUPFUN conv;
|
||||
} ADC_DSET;
|
||||
|
||||
ADC_DSET devWfPentek4261=
|
||||
{6,dev_report,dev_init,dev_init_rec,dev_ioint_info,dev_read,NULL};
|
||||
|
||||
static IOSCANPVT ioscanpvt;
|
||||
static CARD** cards=0;
|
||||
|
||||
static void callback(CALLBACK* cback)
|
||||
{
|
||||
struct dbCommon* pc;
|
||||
struct rset *prset;
|
||||
|
||||
callbackGetUser(pc,cback);
|
||||
prset=(struct rset *)(pc->rset);
|
||||
|
||||
/* process the record */
|
||||
dbScanLock(pc);
|
||||
(*prset->process)(pc);
|
||||
dbScanUnlock(pc);
|
||||
}
|
||||
|
||||
static long dev_report(int level)
|
||||
{
|
||||
int i;
|
||||
volatile ADC* adc_regs;
|
||||
|
||||
if(cards==0)
|
||||
printf("No Pentek ADC cards configured in system\n");
|
||||
else
|
||||
{
|
||||
for(i=0;i<MAX_CARDS;i++)
|
||||
{
|
||||
if(cards[i]!=0)
|
||||
{
|
||||
adc_regs=(ADC*)(i*A16_SIZE+cards[i]->a16_base);
|
||||
|
||||
printf("Pentek 4261A ADC card %d information:\n",i);
|
||||
printf(" a16 base=%8.8x",cards[i]->a16_base);
|
||||
printf(" a32 base=%8.8x\n",cards[i]->a32_base);
|
||||
printf(" irq vector=%d",cards[i]->irq_vector);
|
||||
printf(" irq level=%d\n",cards[i]->irq_level);
|
||||
printf(" word clock=%d",cards[i]->word_clock);
|
||||
printf(" clock frequency=%ld\n",cards[i]->clock_freq);
|
||||
|
||||
printf(" status=%4.4x\n", adc_regs->int_id_status);
|
||||
printf(" int mask=%4.4x\n", adc_regs->int_mask);
|
||||
printf(" command=%4.4x\n", adc_regs->command);
|
||||
printf(" trigger=%4.4x\n", adc_regs->trigger);
|
||||
printf(" int status=%4.4x\n", adc_regs->int_status);
|
||||
}
|
||||
else
|
||||
printf("Pentek 4261A ADC card %d not installed\n",i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dev_init(int after)
|
||||
{
|
||||
if(after) return(0);
|
||||
scanIoInit(&ioscanpvt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dev_init_rec(struct waveformRecord* pr)
|
||||
{
|
||||
volatile ADC* adc_regs;
|
||||
PVT_AREA* pvt;
|
||||
struct vmeio *pvmeio = (struct vmeio *)&(pr->inp.value);
|
||||
char *clock_type,*trigger_type;
|
||||
char parm[40];
|
||||
char** save_area=NULL;
|
||||
|
||||
if(pr->inp.type != VME_IO)
|
||||
{
|
||||
recGblRecordError(S_db_badField,(void *)pr,
|
||||
"devPentekADC (init_record) Illegal INP field");
|
||||
return(S_db_badField);
|
||||
}
|
||||
if(cards[pvmeio->card]==0)
|
||||
{
|
||||
recGblRecordError(S_dev_badCard,(void *)pr,
|
||||
"devPentekADC (init_record) Card not Configured!");
|
||||
return(S_dev_badCard);
|
||||
}
|
||||
if(cards[pvmeio->card]->in_use==1)
|
||||
{
|
||||
recGblRecordError(S_dev_badCard,(void *)pr,
|
||||
"devPentekADC (init_record) Card already in use");
|
||||
return(S_dev_badCard);
|
||||
}
|
||||
if(pr->nelm%cards[pvmeio->card]->word_clock!=0)
|
||||
{
|
||||
recGblRecordError(S_db_badField, (void *)pr,
|
||||
"devPentekADC (init_record) num of elements must be divisible by the word clock");
|
||||
return(S_db_badField);
|
||||
}
|
||||
|
||||
pvt=(PVT_AREA*)malloc(sizeof(PVT_AREA));
|
||||
cards[pvmeio->card]->in_use=1;
|
||||
strcpy(parm,pvmeio->parm);
|
||||
|
||||
if((clock_type=strtok_r(parm,",",save_area))==NULL)
|
||||
{
|
||||
printf("Clock type parameter missing from parm field\n");
|
||||
printf(" Defaulting to i_clock,i_trigger (internal clock/trigger)\n");
|
||||
clock_type="i_clock";
|
||||
trigger_type="i_trigger";
|
||||
}
|
||||
else if((trigger_type=strtok_r(NULL,",",save_area))==NULL)
|
||||
{
|
||||
printf("Triggert type parameter missing from parm field\n");
|
||||
printf(" Defaulting to i_trigger (internal trigger)\n");
|
||||
trigger_type="i_trigger";
|
||||
}
|
||||
|
||||
if( strcmp(clock_type,"i_clock")==0 )
|
||||
pvt->clock_mode=INTERNAL;
|
||||
else if( strcmp(clock_type,"x_clock")==0 )
|
||||
pvt->clock_mode=EXTERNAL;
|
||||
else
|
||||
{
|
||||
printf("Invalid parm for clock type, must be i_clock or x_clock\n");
|
||||
pvt->clock_mode=INTERNAL;
|
||||
}
|
||||
|
||||
if( strcmp(trigger_type,"i_trigger")==0 )
|
||||
pvt->trigger_mode=INTERNAL;
|
||||
else if( strcmp(trigger_type,"x_trigger")==0 )
|
||||
pvt->trigger_mode=EXTERNAL;
|
||||
else
|
||||
{
|
||||
printf("Invalid parm for clock type, must be i_trigger or x_trigger\n");
|
||||
pvt->trigger_mode=INTERNAL;
|
||||
}
|
||||
|
||||
adc_regs=(ADC*)(pvmeio->card*A16_SIZE+cards[pvmeio->card]->a16_base);
|
||||
|
||||
callbackSetCallback(callback,&pvt->callback);
|
||||
callbackSetPriority(pr->prio,&pvt->callback);
|
||||
callbackSetUser(pr,&pvt->callback);
|
||||
|
||||
pvt->adc_regs=adc_regs;
|
||||
pvt->card=pvmeio->card;
|
||||
pvt->file_count=0;
|
||||
pr->dpvt=(void*)pvt;
|
||||
|
||||
/* program number of samples and sample clock */
|
||||
pvt->div=pr->nelm/cards[pvmeio->card]->word_clock;
|
||||
|
||||
/* install the interrupt handler */
|
||||
if(intConnect(INUM_TO_IVEC(cards[pvmeio->card]->irq_vector),
|
||||
(VOIDFUNCPTR)irq_func, (int)pr)!=OK)
|
||||
{ printf("intConnect failed\n"); return -1; }
|
||||
|
||||
sysIntEnable(cards[pvmeio->card]->irq_level);
|
||||
full_reset(pvt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int buffer_reset(PVT_AREA* pvt)
|
||||
{
|
||||
pvt->adc_regs->command=0x00; /* reset the card */
|
||||
pvt->adc_regs->command=0x90; /* vme enable, no reset mode */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int full_reset(PVT_AREA* pvt)
|
||||
{
|
||||
unsigned long clock_div,clock_freq,sample_freq;
|
||||
unsigned short clock_div_short;
|
||||
unsigned char trig;
|
||||
|
||||
buffer_reset(pvt);
|
||||
|
||||
/* auto arm mode not enabled */
|
||||
trig=0x20; /* positive going edge */
|
||||
|
||||
if(pvt->clock_mode==EXTERNAL) trig|=0x08; /* ext clock */
|
||||
|
||||
pvt->adc_regs->trigger=trig; /* set the trigger reg */
|
||||
pvt->adc_regs->int_id_status=cards[pvt->card]->irq_vector;
|
||||
|
||||
/* program counter for bank A */
|
||||
pvt->adc_regs->ctc_control=0x00|0x30|0x04; /* CTC-0,LSB-MSB,mode */
|
||||
pvt->adc_regs->ctc0_bs_a=(unsigned short)(pvt->div&0x00ff);
|
||||
pvt->adc_regs->ctc0_bs_a=(unsigned short)(pvt->div>>8);
|
||||
/* program counter for bank B */
|
||||
pvt->adc_regs->ctc_control=0x40|0x30|0x04; /* CTC-1,LSB-MSB,mode */
|
||||
pvt->adc_regs->ctc1_bs_b=(unsigned short)(pvt->div&0x00ff);
|
||||
pvt->adc_regs->ctc1_bs_b=(unsigned short)(pvt->div>>8);
|
||||
|
||||
/* printf("bank div=%4.4x\n",pvt->div); */
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
careful here, if changing code to use internal clock, use the
|
||||
code below to program the sample clock divisor, remember that if
|
||||
sample clock divisor is one, then the else portion of the code must
|
||||
be used.
|
||||
|
||||
SampleClock = InputClock / N
|
||||
|
||||
where:
|
||||
N is programmed divisor and 1<=N<=65535
|
||||
InputClock is 10MHz for internal clock or the external clock
|
||||
SampleClock if the effective sampling clock
|
||||
|
||||
We are given SampleClock, and need N, so
|
||||
|
||||
N = InputClock / SampleClock
|
||||
*/
|
||||
|
||||
/* internal clock type uses clock_freq from config as sample clock,
|
||||
external clock does not use clock divisor */
|
||||
|
||||
if(pvt->clock_mode==INTERNAL) /* internal clock */
|
||||
{
|
||||
clock_freq=INTERNAL_CLOCK;
|
||||
sample_freq=cards[pvt->card]->clock_freq;
|
||||
}
|
||||
else
|
||||
{
|
||||
clock_freq = cards[pvt->card]->clock_freq;
|
||||
sample_freq = clock_freq;
|
||||
}
|
||||
|
||||
if(clock_freq==sample_freq)
|
||||
{
|
||||
/* if clock divisor of one is to be used (10MHz) */
|
||||
pvt->adc_regs->ctc_control=0x80|0x10; /* CTC-2, LSB, mode 0 */
|
||||
}
|
||||
else
|
||||
{
|
||||
clock_div=clock_freq/sample_freq;
|
||||
/* printf("clock div=%8.8x\n",clock_div); */
|
||||
|
||||
if(clock_div>=1 && clock_div<=65535)
|
||||
{
|
||||
clock_div_short = clock_div;
|
||||
/* if clock divisor used, sample rate */
|
||||
pvt->adc_regs->ctc_control=0x80|0x30|0x04; /* CTC-2,LSB-MSB,mode */
|
||||
pvt->adc_regs->ctc2_clock_div=(clock_div_short&0x00ff);
|
||||
pvt->adc_regs->ctc2_clock_div=(clock_div_short>>8);
|
||||
}
|
||||
else
|
||||
{
|
||||
pvt->adc_regs->ctc_control=0x80|0x10; /* CTC-2, LSB, mode 0 */
|
||||
printf("Invalid clock/sample frequency: %ld/%ld\n",
|
||||
clock_freq,sample_freq);
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
/* start mode = off at this point */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dev_ioint_info(int cmd,struct waveformRecord* pr,IOSCANPVT* iopvt)
|
||||
{
|
||||
PVT_AREA* pvt = (PVT_AREA*)pr->dpvt;
|
||||
|
||||
pr->pact=0;
|
||||
|
||||
if(cmd==CMD_ADDED)
|
||||
setup(pvt);
|
||||
else /* CMD_DELETED */
|
||||
buffer_reset(pvt); /* ensure that we are in a good state */
|
||||
|
||||
*iopvt=ioscanpvt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dev_read(struct waveformRecord* pr)
|
||||
{
|
||||
long rc;
|
||||
PVT_AREA* pvt = (PVT_AREA*)pr->dpvt;
|
||||
|
||||
if(pr->scan==SCAN_IO_EVENT)
|
||||
{
|
||||
pvt->adc_regs->command|=0x20; /* start mode */
|
||||
rc=dev_complete_read(pr);
|
||||
setup(pvt);
|
||||
}
|
||||
else
|
||||
rc=dev_other_read(pr);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long setup(PVT_AREA* pvt)
|
||||
{
|
||||
unsigned char trig;
|
||||
volatile unsigned char istat;
|
||||
|
||||
buffer_reset(pvt);
|
||||
trig=pvt->adc_regs->trigger&0xf8; /* clear run FF,trigger */
|
||||
trig|=0x44; /* external trigger on, auto arm mode */
|
||||
istat=pvt->adc_regs->int_status; /* read int status */
|
||||
pvt->adc_regs->int_mask=0x10; /* bank swap interrupt */
|
||||
pvt->adc_regs->trigger=trig|0x02; /* trigger mode + reset run FF */
|
||||
pvt->adc_regs->command|=0x20; /* start mode */
|
||||
pvt->adc_regs->trigger=trig; /* trigger mode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dev_other_read(struct waveformRecord* pr)
|
||||
{
|
||||
PVT_AREA* pvt = (PVT_AREA*)pr->dpvt;
|
||||
long rc=0;
|
||||
|
||||
if(pr->pact==TRUE)
|
||||
{
|
||||
/* i/o complete */
|
||||
|
||||
/* interrupt handler shut down everything already */
|
||||
pvt->adc_regs->command|=0x20; /* start mode on */
|
||||
rc=dev_complete_read(pr); /* process data in buffer */
|
||||
pvt->adc_regs->command&=~0x20; /* start mode off */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start the i/o */
|
||||
|
||||
/* this sucks, with internal mode trigger, the board glitch
|
||||
every so often, I cannot get it to work correctly, so do full reset */
|
||||
if(pvt->trigger_mode==INTERNAL) full_reset(pvt);
|
||||
|
||||
callbackSetPriority(pr->prio,&pvt->callback);
|
||||
setup(pvt);
|
||||
pr->pact=TRUE;
|
||||
|
||||
if(pvt->trigger_mode==INTERNAL)
|
||||
pvt->adc_regs->trigger|=0x01; /* set run FF */
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long dev_complete_read(struct waveformRecord* pr)
|
||||
{
|
||||
int i;
|
||||
PVT_AREA* pvt = (PVT_AREA*)pr->dpvt;
|
||||
volatile unsigned short* source;
|
||||
volatile unsigned short samples;
|
||||
|
||||
source=&(pvt->adc_regs->vme_fifo);
|
||||
i=0;
|
||||
|
||||
switch(pr->ftvl)
|
||||
{
|
||||
case DBF_FLOAT:
|
||||
{
|
||||
float* f_thing = (float*)pr->bptr;
|
||||
|
||||
for(i=0;i<pr->nelm;i++)
|
||||
{
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
f_thing[i]=(float)(((short)samples)>>4);
|
||||
}
|
||||
pr->nord=i;
|
||||
break;
|
||||
}
|
||||
case DBF_DOUBLE:
|
||||
{
|
||||
double* d_thing = (double*)pr->bptr;
|
||||
|
||||
for(i=0;i<pr->nelm;i++)
|
||||
{
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
d_thing[i]=(double)(((short)samples)>>4);
|
||||
}
|
||||
pr->nord=i;
|
||||
break;
|
||||
}
|
||||
case DBF_ULONG:
|
||||
{
|
||||
unsigned long* ul_thing = (unsigned long*)pr->bptr;
|
||||
|
||||
for(i=0;i<pr->nelm;i++)
|
||||
{
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
ul_thing[i]=(unsigned long)((samples>>4)&0x0fff);
|
||||
}
|
||||
pr->nord=i;
|
||||
break;
|
||||
}
|
||||
case DBF_LONG:
|
||||
{
|
||||
long* l_thing = (long*)pr->bptr;
|
||||
|
||||
for(i=0;i<pr->nelm;i++)
|
||||
{
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
l_thing[i]=(long)(((long)samples)>>4);
|
||||
}
|
||||
pr->nord=i;
|
||||
break;
|
||||
}
|
||||
case DBF_USHORT:
|
||||
{
|
||||
unsigned short* s_thing = (unsigned short*)pr->bptr;
|
||||
|
||||
for(i=0;i<pr->nelm;i++)
|
||||
{
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
s_thing[i]=(unsigned short)((samples>>4)&0x0fff);
|
||||
}
|
||||
pr->nord=i;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("devPentek4261: Invalid data type\n");
|
||||
case DBF_SHORT:
|
||||
{
|
||||
short* ss_thing = (unsigned short*)pr->bptr;
|
||||
|
||||
for(i=0;i<pr->nelm;i++)
|
||||
{
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
ss_thing[i]=(short)(((short)(samples))>>4);
|
||||
}
|
||||
pr->nord=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* clear remaining samples if any */
|
||||
while(pvt->adc_regs->int_id_status&0x80)
|
||||
samples=pvt->adc_regs->vme_fifo;
|
||||
|
||||
/* pr->nelm, pr->bptr, &(pr->nord) */ /* three important fields */
|
||||
pr->udf=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IRQ under vxWorks */
|
||||
static void irq_func(void* v)
|
||||
{
|
||||
struct waveformRecord* pr = (struct waveformRecord*)v;
|
||||
PVT_AREA* pvt = (PVT_AREA*)pr->dpvt;
|
||||
CALLBACK* cb = (CALLBACK*)pvt;
|
||||
unsigned char trig;
|
||||
|
||||
pvt->last_int_status=pvt->adc_regs->int_status; /* read status */
|
||||
|
||||
/* logMsg("in irq_func\n"); */
|
||||
/* if(pvt->last_int_status&0x02) logMsg("Overrun error\n"); */
|
||||
|
||||
pvt->adc_regs->command&=~0x20; /* start mode off - freeze all */
|
||||
pvt->adc_regs->int_mask=0x00; /* interrupts off */
|
||||
trig=pvt->adc_regs->trigger&0xfc; /* clear run FF bits */
|
||||
pvt->adc_regs->trigger=trig; /* clear run FF bits */
|
||||
pvt->adc_regs->trigger=trig|0x02; /* force reset run FF */
|
||||
|
||||
if(pr->scan==SCAN_IO_EVENT)
|
||||
scanIoRequest(ioscanpvt); /* scan EPICS record */
|
||||
else
|
||||
callbackRequest(cb);
|
||||
}
|
||||
|
||||
void ReportPentekADC() { dev_report(0); }
|
||||
|
||||
void ConfigurePentekADC( int card,
|
||||
unsigned long a16_base, unsigned long a32_base,
|
||||
int irq_vector, int irq_level,
|
||||
int word_clock, unsigned long clock_freq)
|
||||
{
|
||||
unsigned short dummy;
|
||||
|
||||
if(cards==0)
|
||||
{
|
||||
cards=(CARD**)malloc(sizeof(CARD*)*MAX_CARDS);
|
||||
memset((char*)cards,0,sizeof(CARD*)*MAX_CARDS);
|
||||
}
|
||||
|
||||
if(cards[card]!=0) printf("Overriding previous configuration\n");
|
||||
else cards[card]=(CARD*)malloc(sizeof(CARD));
|
||||
|
||||
cards[card]->in_use=0;
|
||||
if( sysBusToLocalAdrs(VME_AM_SUP_SHORT_IO,(char*)a16_base,(char**)&(cards[card]->a16_base))!=OK)
|
||||
{
|
||||
printf(" a16 base could not be converted\n");
|
||||
}
|
||||
if( sysBusToLocalAdrs(VME_AM_EXT_SUP_DATA,(char*)a32_base,(char**)&(cards[card]->a32_base))!=OK)
|
||||
{
|
||||
printf(" a32 base could not be converted\n");
|
||||
}
|
||||
cards[card]->irq_vector=irq_vector;
|
||||
cards[card]->irq_level=irq_level;
|
||||
cards[card]->word_clock=word_clock;
|
||||
cards[card]->clock_freq=clock_freq;
|
||||
|
||||
if(vxMemProbe((char*)cards[card]->a16_base,READ,
|
||||
sizeof(unsigned short),(char*)&dummy)!=OK)
|
||||
{
|
||||
/* card not really present */
|
||||
cards[card]->in_use=1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user