These boards can support external multiplexors and multi-board
synchronization, but this driver doesn't support that.
- Board docs: http://www.rtdusa.com/dm7520.htm
+ Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm
Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
Call them and ask for the register level manual.
/*
The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128)
*/
-static comedi_lrange rtd_ai_7520_range = { 6, {
+static comedi_lrange rtd_ai_7520_range = { 18, {
+ /* +-5V input range gain steps */
BIP_RANGE(5.0),
BIP_RANGE(5.0/2),
BIP_RANGE(5.0/4),
BIP_RANGE(5.0/8),
BIP_RANGE(5.0/16),
BIP_RANGE(5.0/32),
-#if 0 /* until we can handle 10V mode */
+ /* +-10V input range gain steps */
+ BIP_RANGE(10.0),
+ BIP_RANGE(10.0/2),
+ BIP_RANGE(10.0/4),
+ BIP_RANGE(10.0/8),
+ BIP_RANGE(10.0/16),
+ BIP_RANGE(10.0/32),
+ /* +10V input range gain steps */
UNI_RANGE(10.0),
UNI_RANGE(10.0/2),
UNI_RANGE(10.0/4),
UNI_RANGE(10.0/8),
UNI_RANGE(10.0/16),
UNI_RANGE(10.0/32),
-#endif
+
}};
/* PCI4520 has two more gains (6 more entries) */
-static comedi_lrange rtd_ai_4520_range = { 8, {
+static comedi_lrange rtd_ai_4520_range = { 24, {
+ /* +-5V input range gain steps */
BIP_RANGE(5.0),
BIP_RANGE(5.0/2),
BIP_RANGE(5.0/4),
BIP_RANGE(5.0/32),
BIP_RANGE(5.0/64),
BIP_RANGE(5.0/128),
-#if 0 /* until we can handle 10V mode */
+ /* +-10V input range gain steps */
+ BIP_RANGE(10.0),
+ BIP_RANGE(10.0/2),
+ BIP_RANGE(10.0/4),
+ BIP_RANGE(10.0/8),
+ BIP_RANGE(10.0/16),
+ BIP_RANGE(10.0/32),
+ BIP_RANGE(10.0/64),
+ BIP_RANGE(10.0/128),
+ /* +10V input range gain steps */
UNI_RANGE(10.0),
UNI_RANGE(10.0/2),
UNI_RANGE(10.0/4),
UNI_RANGE(10.0/32),
UNI_RANGE(10.0/64),
UNI_RANGE(10.0/128),
-#endif
}};
/* Table order matches range values */
int aiBits;
int aiMaxGain;
int fifoLen;
+ int range10Start; /* start of +-10V range */
+ int rangeUniStart; /* start of +10V range */
} rtdBoard;
static rtdBoard rtd520Boards[] = {
aiBits: 12,
aiMaxGain: 32,
fifoLen: 1024,
+ range10Start: 6,
+ rangeUniStart: 12,
},
{
name: "DM7520-8",
aiBits: 12,
aiMaxGain: 32,
fifoLen: 8192,
+ range10Start: 6,
+ rangeUniStart: 12,
},
{
name: "PCI4520",
aiBits: 12,
aiMaxGain: 128,
fifoLen: 1024,
+ range10Start: 8,
+ rangeUniStart: 16,
},
{
name: "PCI4520-8",
aiBits: 12,
aiMaxGain: 128,
fifoLen: 8192,
+ range10Start: 8,
+ rangeUniStart: 16,
},
};
unsigned long intCount; /* interrupt count */
unsigned long aiCount; /* total transfer size (samples) */
unsigned long aiExtraInt; /* ints but no data */
- int aboutWrap;
+ int transCount; /* # to tranfer data. 0->1/2FIFO*/
+ int aboutWrap; /* number of about overflows needed */
/* PCI device info */
struct pci_dev *pci_dev;
s->insn_bits = rtd_dio_insn_bits;
s->insn_config = rtd_dio_insn_config;
- /* timer/counter subdevices */
+ /* timer/counter subdevices (not currently supported) */
s=dev->subdevices+3;
s->type = COMEDI_SUBD_COUNTER;
s->subdev_flags=SDF_READABLE|SDF_WRITEABLE;
- //s->insn_read= rtd_gpct_insn_read;
- //s->insn_write= rtd_gpct_insn_write;
- //s->insn_config=rtd_gpct_insn_config;
s->n_chan=3;
s->maxdata=0xffff;
RtdUtcCtrlPut (dev, 1, 0x30); /* safe state, set shadow */
RtdUtcCtrlPut (dev, 2, 0x30); /* safe state, set shadow */
RtdUtcCtrlPut (dev, 3, 0); /* safe state, set shadow */
- /* todo: set user out source ??? */
+ /* TODO: set user out source ??? */
if (dev->irq) { /* enable interrupt controller */
RtdPLXInterruptWrite (dev,
Convert a single comedi channel-gain entry to a RTD520 table entry
*/
static unsigned short rtdConvertChanGain (
+ comedi_device *dev,
unsigned int comediChan)
{
unsigned int chan, range, aref;
r |= chan & 0xf;
- /* TODO: Should also be able to switch into +-=10 range */
- /* HACK!!! should not use a constant here */
- if (range < 6) { /* first 6 are bipolar */
+ if (range < thisboard->range10Start) {/* first batch are +-5 */
r |= 0x000; /* +-5 range */
r |= (range & 0x7) << 4; /* gain */
- } else {
+ } else if (range < thisboard->rangeUniStart) {/* second batch are +-10 */
+ r |= 0x100; /* +-10 range */
+ r |= ((range - thisboard->range10Start) & 0x7) << 4; /* gain */
+ } else { /* last batch is +10 */
r |= 0x200; /* +10 range */
- r |= ((range-6) & 0x7) << 4; /* gain */
+ r |= ((range-thisboard->rangeUniStart) & 0x7) << 4; /* gain */
}
switch (aref) {
RtdClearCGT (dev);
RtdEnableCGT(dev, 1); /* enable table */
for(ii=0; ii < n_chan; ii++){
- RtdWriteCGTable (dev, rtdConvertChanGain (list[ii]));
+ RtdWriteCGTable (dev, rtdConvertChanGain (dev, list[ii]));
}
} else { /* just use the channel gain latch */
RtdEnableCGT(dev, 0); /* disable table, enable latch */
- RtdWriteCGLatch (dev, rtdConvertChanGain (list[0]));
+ RtdWriteCGLatch (dev, rtdConvertChanGain (dev, list[0]));
}
}
}
/*
- Fifo is a least half full. Get what we know is there.... Fast!
+ Get what we know is there.... Fast!
This uses 1/2 the bus cycles of read_dregs (below).
The manual claims that we can do a lword read, but it doesn't work here.
*/
-static void ai_read_half_fifo (
+static void ai_read_n (
comedi_device *dev,
- comedi_subdevice *s)
+ comedi_subdevice *s,
+ int count)
{
int ii;
- for (ii = 0; ii < thisboard->fifoLen / 2; ii++) {
+ for (ii = 0; ii < count; ii++) {
s16 d = RtdAdcFifoGet (dev); /* get 2s comp value */
d = d >> 3; /* low 3 bits are marker lines */
if (status & (IRQM_ADC_ABOUT_CNT | IRQM_ADC_SAMPLE_CNT)) {
comedi_subdevice *s = dev->subdevices + 0; /* analog in subdevice */
- /* Check for any ready data */
- if (RtdFifoStatus (dev) & FS_ADC_HEMPTY) { /* read 1/2 fifo worth */
- ai_read_half_fifo (dev, s);
- s->async->events |= COMEDI_CB_BLOCK; /* signal something there */
- } else {
- /* for slow transfers, we should read whatever is there */
- /*s->async->events |= COMEDI_CB_EOS;*/
+ if (devpriv->transCount > 0) { /* read often */
+ if (status & IRQM_ADC_SAMPLE_CNT) {
+ ai_read_n (dev, s, devpriv->transCount);
+ s->async->events |= COMEDI_CB_BLOCK;
+ /*s->async->events |= COMEDI_CB_EOS;*/
+ }
+ } else { /* wait for 1/2 FIFO */
+ if (RtdFifoStatus (dev) & FS_ADC_HEMPTY) {
+ ai_read_n (dev, s, thisboard->fifoLen / 2);
+ s->async->events |= COMEDI_CB_BLOCK;
+ }
}
if (0 == devpriv->aiCount) { /* done! stop! */
}
}
- /* check for fifo over-run */
+ /* TODO: check for fifo over-run */
comedi_event (dev, s, s->async->events);
}
if (cmd->start_arg != 0) {
cmd->start_arg = 0;
- DPRINTK ("rtd520: cmdtest: start_arg not 0\n");
err++;
}
if (cmd->scan_begin_src == TRIG_TIMER){
if (cmd->scan_begin_arg < RTD_MAX_SPEED) {
cmd->scan_begin_arg = RTD_MAX_SPEED;
- DPRINTK ("rtd520: cmdtest: scan rate greater than max.\n");
err++;
}
if (cmd->scan_begin_arg > RTD_MIN_SPEED) {
cmd->scan_begin_arg = RTD_MIN_SPEED;
- DPRINTK ("rtd520: cmdtest: scan rate lower than min.\n");
err++;
}
} else {
/* should specify multiple external triggers */
if (cmd->scan_begin_arg > 9) {
cmd->scan_begin_arg = 9;
- DPRINTK ("rtd520: cmdtest: scan_begin_arg out of range\n");
err++;
}
}
if (cmd->convert_src==TRIG_TIMER) {
if (cmd->convert_arg < RTD_MAX_SPEED) {
cmd->convert_arg = RTD_MAX_SPEED;
- DPRINTK ("rtd520: cmdtest: convert rate greater than max.\n");
err++;
}
if (cmd->convert_arg > RTD_MIN_SPEED) {
cmd->convert_arg = RTD_MIN_SPEED;
- DPRINTK ("rtd520: cmdtest: convert rate lower than min.\n");
err++;
}
} else {
/* see above */
if (cmd->convert_arg > 9) {
cmd->convert_arg = 9;
- DPRINTK ("rtd520: cmdtest: convert_arg out of range\n");
err++;
}
}
/* TRIG_NONE */
if (cmd->stop_arg!=0) {
cmd->stop_arg=0;
- DPRINTK ("rtd520: cmdtest: stop_arg not 0\n");
err++;
}
}
if (err) {
- DPRINTK ("rtd520: cmdtest error! Some argument compatibility test failed.\n");
return 3;
}
}
if (err) {
- DPRINTK ("rtd520: cmdtest error! Some timer value was altered.\n");
return 4;
}
RtdAdcConversionSource (dev, 1); /* PACER triggers ADC */
}
- RtdAdcSampleCounter (dev, /* setup a periodic interrupt */
- (thisboard->fifoLen > 1024) ? 1023 : 511);
+ /* arrange to transfer data about every 10ms */
+ if (TRIG_TIMER == cmd->scan_begin_src) {
+ /* scan_begin_arg is in nanoseconds */
+ /* find out how many samples to wait before transferring */
+ devpriv->transCount = (10000000*cmd->chanlist_len)/cmd->scan_begin_arg;
+ if (devpriv->transCount < cmd->chanlist_len) {
+ /* tranfer after each scan (and avoid 0) */
+ devpriv->transCount = cmd->chanlist_len;
+ }
+ DPRINTK ("rtd520: tranferCount=%d scanTime(ns)=%d scanLen=%d\n",
+ devpriv->transCount, cmd->scan_begin_arg, cmd->chanlist_len);
+ if (devpriv->transCount > ((thisboard->fifoLen > 1024) ? 1024 : 512)) {
+ /* out of counter range, use 1/2 fifo instead */
+ devpriv->transCount = 0;
+ RtdAdcSampleCounter (dev,
+ (thisboard->fifoLen > 1024) ? 1023 : 511);
+ } else {
+ /* interupt for each tranfer */
+ RtdAdcSampleCounter (dev, devpriv->transCount-1);
+ }
+ } else {
+ devpriv->transCount = 0;
+ RtdAdcSampleCounter (dev, /* setup a periodic interrupt */
+ (thisboard->fifoLen > 1024) ? 1023 : 511);
+ }
RtdPacerStopSource (dev, 3); /* stop on ABOUT count down*/
RtdAboutStopEnable (dev, 0); /* actually stop (see below) */
RtdPacerClockSource (dev, 1); /* use INTERNAL 8Mhz clock source */
break;
}
if (ii >= RTD_ADC_TIMEOUT) {
- DPRINTK ("rtd520: ai_cmd Error: Never got data in FIFO! FifoStatus=0x%x\n",
+ DPRINTK ("rtd520 ai_cmd Error! Never got data in FIFO! FifoStatus=0x%x\n",
stat);
return -ETIMEDOUT;
}