These boards may be autocalibrated with the comedi_calibrate utility.
To select the bnc trigger input on the 4020 (instead of the dio input),
-specify channel 1000 in the chanspec.
-Feel free to send and success/failure reports to Frank Hess.
+specify channel 1000 in the chanspec. If you wish to use an external
+master clock on the 4020, you may do so by setting the scan_begin_src
+to TRIG_OTHER, and using an INSN_CONFIG_TIMER_1 configuration insn
+to configure the divisor to use for the external clock.
Some devices are not identified because the PCI device IDs are not yet
-known. If you have such a board, contact Frank Hess and the ID can be
-easily added.
+known. If you have such a board, please file a bug report at
+https://bugs.comedi.org.
*/
* (and the maximum number of dma buffers we maintain) */
#define DMA_RING_COUNT 64
-// arbitrary channel number used to select bnc trigger input
-static const int bnc_trigger_channel_4020 = 1000;
-
/* PCI-DAS64xxx base addresses */
// indices of base address regions
struct ext_clock_info
{
- unsigned int convert_divisor; // master clock divisor to use for conversions with external master clock
- unsigned int scan_divisor; // master clock divisor to use for scans with external master clock
- unsigned int chanspec; // chanspec for master clock input
+ unsigned int divisor; // master clock divisor to use for scans with external master clock
+ unsigned int chanspec; // chanspec for master clock input when used as scan begin src
};
/* this structure is for data unique to this hardware driver. */
static void ad8402_write( comedi_device *dev, unsigned int channel, unsigned int value );
static int ad8402_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);
static int eeprom_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data);
-static void check_adc_timing(comedi_cmd *cmd);
+static void check_adc_timing( comedi_device *dev, comedi_cmd *cmd);
static unsigned int get_divisor(unsigned int ns, unsigned int flags);
static void i2c_write(comedi_device *dev, unsigned int address, const uint8_t *data, unsigned int length);
static void caldac_write( comedi_device *dev, unsigned int channel, unsigned int value );
switch( data[1] )
{
case COMEDI_EV_SCAN_BEGIN:
- priv(dev)->ext_clock.scan_divisor = divisor;
+ priv(dev)->ext_clock.divisor = divisor;
priv(dev)->ext_clock.chanspec = data[2];
break;
default:
if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++;
tmp = cmd->convert_src;
+ triggers = TRIG_TIMER;
if(board(dev)->layout == LAYOUT_4020)
- triggers = TRIG_NOW | TRIG_OTHER;
+ triggers |= TRIG_NOW;
else
- triggers = TRIG_TIMER | TRIG_EXT;
+ triggers |= TRIG_EXT;
cmd->convert_src &= triggers;
if(!cmd->convert_src || tmp != cmd->convert_src) err++;
cmd->scan_begin_src != TRIG_FOLLOW) err++;
if(cmd->convert_src != TRIG_TIMER &&
cmd->convert_src != TRIG_EXT &&
- cmd->convert_src != TRIG_NOW &&
- cmd->convert_src != TRIG_OTHER) err++;
+ cmd->convert_src != TRIG_NOW ) err++;
if(cmd->stop_src != TRIG_COUNT &&
cmd->stop_src != TRIG_NONE &&
cmd->stop_src != TRIG_EXT) err++;
if(cmd->stop_src != TRIG_COUNT &&
cmd->stop_src != TRIG_NONE &&
cmd->stop_src != TRIG_EXT) err++;
- if( cmd->convert_src == TRIG_OTHER &&
- cmd->scan_begin_arg == TRIG_OTHER ) err++;
-
+
if(err) return 2;
/* step 3: make sure arguments are trivially compatible */
if(cmd->convert_src == TRIG_TIMER)
{
- if(cmd->convert_arg < board(dev)->ai_speed)
+ if(board(dev)->layout == LAYOUT_4020)
{
- cmd->convert_arg = board(dev)->ai_speed;
- err++;
- }
- if(cmd->scan_begin_src == TRIG_TIMER)
+ if( cmd->convert_arg )
+ {
+ cmd->convert_arg = 0;
+ err++;
+ }
+ }else
{
- // if scans are timed faster than conversion rate allows
- if(cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg)
+ if(cmd->convert_arg < board(dev)->ai_speed)
{
- cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len;
+ cmd->convert_arg = board(dev)->ai_speed;
err++;
}
+ if(cmd->scan_begin_src == TRIG_TIMER)
+ {
+ // if scans are timed faster than conversion rate allows
+ if(cmd->convert_arg * cmd->chanlist_len > cmd->scan_begin_arg)
+ {
+ cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len;
+ err++;
+ }
+ }
}
}
{
tmp_arg = cmd->convert_arg;
tmp_arg2 = cmd->scan_begin_arg;
- check_adc_timing(cmd);
+ check_adc_timing( dev, cmd);
if(tmp_arg != cmd->convert_arg) err++;
if(tmp_arg2 != cmd->scan_begin_arg) err++;
}
// figure out how long we need to delay at end of scan
switch( cmd->scan_begin_src )
{
- case TRIG_TIMER:
- return ( cmd->scan_begin_arg - ( cmd->convert_arg * ( cmd->chanlist_len - 1 ) ) )
- / TIMER_BASE;
- break;
- case TRIG_FOLLOW:
- return cmd->convert_arg / TIMER_BASE;
- break;
- default:
- break;
+ case TRIG_TIMER:
+ return ( cmd->scan_begin_arg - ( cmd->convert_arg * ( cmd->chanlist_len - 1 ) ) )
+ / TIMER_BASE;
+ break;
+ case TRIG_FOLLOW:
+ return cmd->convert_arg / TIMER_BASE;
+ break;
+ default:
+ break;
}
return 0;
}
switch( cmd->scan_begin_src )
{
- case TRIG_TIMER:
- divisor = cmd->scan_begin_arg;
- break;
- case TRIG_OTHER:
- divisor = priv(dev)->ext_clock.scan_divisor;
- break;
- default: // should never happen
- comedi_error( dev, "bug! failed to set ai pacing!" );
- divisor = 1000;
- break;
+ case TRIG_TIMER:
+ divisor = cmd->scan_begin_arg / TIMER_BASE;
+ break;
+ case TRIG_OTHER:
+ divisor = priv(dev)->ext_clock.divisor;
+ break;
+ default: // should never happen
+ comedi_error( dev, "bug! failed to set ai pacing!" );
+ divisor = 1000;
+ break;
}
// supposed to load counter with desired divisor minus 2 for 4020
- return divisor / TIMER_BASE - 2;
+ return divisor - 2;
}
static void select_master_clock_4020( comedi_device *dev, const comedi_cmd *cmd )
{
- int chanspec = priv(dev)->ext_clock.chanspec;
-
// select internal/external master clock
priv(dev)->hw_config_bits &= ~MASTER_CLOCK_4020_MASK;
if( cmd->scan_begin_src == TRIG_OTHER )
{
- if( CR_CHAN( chanspec ) == bnc_trigger_channel_4020 )
+ int chanspec = priv(dev)->ext_clock.chanspec;
+
+ if( CR_CHAN( chanspec ) )
priv(dev)->hw_config_bits |= BNC_CLOCK_4020_BITS;
else
priv(dev)->hw_config_bits |= EXT_CLOCK_4020_BITS;
{
uint32_t convert_counter = 0, scan_counter = 0;
- check_adc_timing( cmd );
+ check_adc_timing( dev, cmd );
select_master_clock( dev, cmd );
/* set source for external triggers */
bits = 0;
if( cmd->start_src == TRIG_EXT &&
- CR_CHAN( cmd->start_arg ) == bnc_trigger_channel_4020 )
+ CR_CHAN( cmd->start_arg ) )
bits |= EXT_START_TRIG_BNC_BIT;
if( cmd->stop_src == TRIG_EXT &&
- CR_CHAN( cmd->stop_arg ) == bnc_trigger_channel_4020 )
+ CR_CHAN( cmd->stop_arg ) )
bits |= EXT_STOP_TRIG_BNC_BIT;
writew( bits, priv(dev)->main_iobase + DAQ_ATRIG_LOW_4020_REG );
}
* sets cmd members appropriately.
* adc paces conversions from master clock by dividing by (x + 3) where x is 24 bit number
*/
-static void check_adc_timing(comedi_cmd *cmd)
+static void check_adc_timing( comedi_device *dev, comedi_cmd *cmd)
{
unsigned int convert_divisor = 0, scan_divisor;
static const int max_counter_value = 0xffffff; // board uses 24 bit counters for pacing
if(cmd->convert_src == TRIG_TIMER)
{
- convert_divisor = get_divisor(cmd->convert_arg, cmd->flags);
- if(convert_divisor > max_convert_divisor) convert_divisor = max_convert_divisor;
- if(convert_divisor < min_convert_divisor) convert_divisor = min_convert_divisor;
- cmd->convert_arg = convert_divisor * TIMER_BASE;
+ if( board(dev)->layout == LAYOUT_4020 )
+ {
+ cmd->convert_arg = 0;
+ }else
+ {
+ convert_divisor = get_divisor(cmd->convert_arg, cmd->flags);
+ if(convert_divisor > max_convert_divisor) convert_divisor = max_convert_divisor;
+ if(convert_divisor < min_convert_divisor) convert_divisor = min_convert_divisor;
+ cmd->convert_arg = convert_divisor * TIMER_BASE;
+ }
}else if(cmd->convert_src == TRIG_NOW)
cmd->convert_arg = 0;