📄 cb_pcidas64.c
字号:
/* cb_pcidas64.c This is a driver for the ComputerBoards/MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 cards. Author: Frank Mori Hess <fmhess@users.sourceforge.net> Copyright (C) 2001, 2002 Frank Mori Hess Thanks also go to the following people: Steve Rosenbluth, for providing the source code for his pci-das6402 driver, and source code for working QNX pci-6402 drivers by Greg Laird and Mariusz Bogacz. None of the code was used directly here, but it was useful as an additional source of documentation on how to program the boards. John Sims, for much testing and feedback on pcidas-4020 support. COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.************************************************************************//*Driver: cb_pcidas64.oDescription: Driver for the ComputerBoards/MeasurementComputing PCI-DAS64xx, 60XX, and 4020 series with the PLX 9080 PCI controller.Author: Frank Mori Hess <fmhess@users.sourceforge.net>Status: works, but no streaming analog output yetUpdated: 2002-07-18Devices: [Measurement Computing] PCI-DAS6402/16 (cb_pcidas64), PCI-DAS6402/12, PCI-DAS64/M1/16, PCI-DAS64/M2/16, PCI-DAS64/M3/16, PCI-DAS6402/16/JR, PCI-DAS64/M1/16/JR, PCI-DAS64/M2/16/JR, PCI-DAS64/M3/16/JR, PCI-DAS64/M1/14, PCI-DAS64/M2/14, PCI-DAS64/M3/14, PCI-DAS6023, PCI-DAS6025, PCI-DAS6030, PCI-DAS6031, PCI-DAS6032, PCI-DAS6033, PCI-DAS6034, PCI-DAS6035, PCI-DAS6036, PCI-DAS6040, PCI-DAS6052, PCI-DAS6070, PCI-DAS6071, PCI-DAS4020/12Configuration options: [0] - PCI bus of device (optional) [1] - PCI slot of device (optional)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.Some devices are not identified because the PCI device IDs are not yetknown. If you have such a board, contact Frank Hess and the ID can beeasily added.*//*TODO: command support for ao user counter subdevice there are a number of boards this driver will support when they are fully released, but does not yet since the pci device id numbers are not yet available. support prescaled 100khz clock for slow pacing (not available on 6000 series?)*/#include <linux/comedidev.h>#include <linux/delay.h>#include <linux/pci.h>#include "8253.h"#include "8255.h"#include "plx9080.h"#include "comedi_fc.h"#undef PCIDAS64_DEBUG // disable debugging code//#define PCIDAS64_DEBUG // enable debugging code#ifdef PCIDAS64_DEBUG#define DEBUG_PRINT(format, args...) rt_printk(format , ## args )#else#define DEBUG_PRINT(format, args...)#endif#define TIMER_BASE 25 // 40MHz master clock#define PRESCALED_TIMER_BASE 10000 // 100kHz 'prescaled' clock for slow aquisition, maybe I'll support this someday#define DMA_BUFFER_SIZE 0x1000/* maximum number of dma transfers we will chain together into a ring * (and the maximum number of dma buffers we maintain) */#define DMA_RING_COUNT 64// arbitrary channel number used to select bnc trigger inputstatic const int bnc_trigger_channel_4020 = 1000;/* PCI-DAS64xxx base addresses */// indices of base address regionsenum base_address_regions{ PLX9080_BADDRINDEX = 0, MAIN_BADDRINDEX = 2, DIO_COUNTER_BADDRINDEX = 3,};// priv(dev)->main_iobase registersenum write_only_registers{ INTR_ENABLE_REG = 0x0, // interrupt enable register HW_CONFIG_REG = 0x2, // hardware config register DAQ_SYNC_REG = 0xc, DAQ_ATRIG_LOW_4020_REG = 0xc, ADC_CONTROL0_REG = 0x10, // adc control register 0 ADC_CONTROL1_REG = 0x12, // adc control register 1 CALIBRATION_REG = 0x14, ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, // lower 16 bits of sample interval counter ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, // upper 8 bits of sample interval counter ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, // lower 16 bits of delay interval counter ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, // upper 8 bits of delay interval counter ADC_COUNT_LOWER_REG = 0x1e, // lower 16 bits of hardware conversion/scan counter ADC_COUNT_UPPER_REG = 0x20, // upper 8 bits of hardware conversion/scan counter ADC_START_REG = 0x22, // software trigger to start aquisition ADC_CONVERT_REG = 0x24, // initiates single conversion ADC_QUEUE_CLEAR_REG = 0x26, // clears adc queue ADC_QUEUE_LOAD_REG = 0x28, // loads adc queue ADC_BUFFER_CLEAR_REG = 0x2a, ADC_QUEUE_HIGH_REG = 0x2c, // high channel for internal queue, use adc_chan_bits() inline above DAC_CONTROL0_REG = 0x50, // dac control register 0 DAC_CONTROL1_REG = 0x52, // dac control register 0 DAC_BUFFER_CLEAR_REG = 0x66, // clear dac buffer};static inline unsigned int dac_convert_reg( unsigned int channel ){ return 0x70 + ( 2 * ( channel & 0x1 ) );}static inline unsigned int dac_lsb_4020_reg( unsigned int channel ){ return 0x70 + ( 4 * ( channel & 0x1 ) );}static inline unsigned int dac_msb_4020_reg( unsigned int channel ){ return 0x72 + ( 4 * ( channel & 0x1 ) );}enum read_only_registers{ HW_STATUS_REG = 0x0, // hardware status register, reading this apparently clears pending interrupts as well PIPE1_READ_REG = 0x4, ADC_READ_PNTR_REG = 0x8, LOWER_XFER_REG = 0x10, ADC_WRITE_PNTR_REG = 0xc, PREPOST_REG = 0x14,};enum read_write_registers{ I8255_4020_REG = 0x48, // 8255 offset, for 4020 only ADC_QUEUE_FIFO_REG = 0x100, // external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG ADC_FIFO_REG = 0x200, // adc data fifo};// priv(dev)->dio_counter_iobase registersenum dio_counter_registers{ DIO_8255_OFFSET = 0x0, DO_REG = 0x20, DI_REG = 0x28, DIO_DIRECTION_60XX_REG = 0x40, DIO_DATA_60XX_REG = 0x48,};// bit definitions for write-only registersenum intr_enable_contents{ ADC_INTR_SRC_MASK = 0x3, // bits that set adc interrupt source ADC_INTR_QFULL_BITS = 0x0, // interrupt fifo quater full ADC_INTR_EOC_BITS = 0x1, // interrupt end of conversion ADC_INTR_EOSCAN_BITS = 0x2, // interrupt end of scan ADC_INTR_EOSEQ_BITS = 0x3, // interrupt end of sequence (probably wont use this it's pretty fancy) EN_ADC_INTR_SRC_BIT = 0x4, // enable adc interrupt source EN_ADC_DONE_INTR_BIT = 0x8, // enable adc aquisition done interrupt EN_DAC_INTR_SRC_BIT = 0x40, // enable dac interrupt source EN_ADC_ACTIVE_INTR_BIT = 0x200, // enable adc active interrupt EN_ADC_STOP_INTR_BIT = 0x400, // enable adc stop trigger interrupt EN_DAC_ACTIVE_INTR_BIT = 0x800, // enable dac active interrupt EN_DAC_UNDERRUN_BIT = 0x4000, // enable dac underrun status bit EN_ADC_OVERRUN_BIT = 0x8000, // enable adc overrun status bit};enum hw_config_contents{ MASTER_CLOCK_4020_MASK = 0x3, // bits that specify master clock source for 4020 INTERNAL_CLOCK_4020_BITS = 0x1, // use 40 MHz internal master clock for 4020 BNC_CLOCK_4020_BITS = 0x2, // use BNC input for master clock EXT_CLOCK_4020_BITS = 0x3, // use dio input for master clock EXT_QUEUE_BIT = 0x200, // use external channel/gain queue (more versatile than internal queue) SLOW_DAC_BIT = 0x400, // use 225 nanosec strobe when loading dac instead of 50 nanosec HW_CONFIG_DUMMY_BITS = 0x2000, // bit with unknown function yet given as default value in pci-das64 manual DMA_CH_SELECT_BIT = 0x8000, // bit selects channels 1/0 for analog input/output, otherwise 0/1 FIFO_SIZE_REG = 0x4, // allows adjustment of fifo sizes, we will always use maximum DAC_FIFO_SIZE_MASK = 0xff00, // bits that set dac fifo size DAC_FIFO_BITS = 0xf000,};enum daq_atrig_low_4020_contents{ EXT_AGATE_BNC_BIT = 0x8000, // use trig/ext clk bnc input for analog gate signal EXT_STOP_TRIG_BNC_BIT = 0x4000, // use trig/ext clk bnc input for external stop trigger signal EXT_START_TRIG_BNC_BIT = 0x2000, // use trig/ext clk bnc input for external start trigger signal};static inline uint16_t analog_trig_low_threshold_bits( uint16_t threshold ){ return threshold & 0xfff;}enum adc_control0_contents{ ADC_GATE_SRC_MASK = 0x3, // bits that select gate ADC_SOFT_GATE_BITS = 0x1, // software gate ADC_EXT_GATE_BITS = 0x2, // external digital gate ADC_ANALOG_GATE_BITS = 0x3, // analog level gate ADC_GATE_LEVEL_BIT = 0x4, // level-sensitive gate (for digital) ADC_GATE_POLARITY_BIT = 0x8, // gate active low ADC_START_TRIG_SOFT_BITS = 0x10, ADC_START_TRIG_EXT_BITS = 0x20, ADC_START_TRIG_ANALOG_BITS = 0x30, ADC_START_TRIG_MASK = 0x30, ADC_START_TRIG_FALLING_BIT = 0x40, // trig 1 uses falling edge ADC_EXT_CONV_FALLING_BIT = 0x800, // external pacing uses falling edge ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, // enable hardware scan counter ADC_DMA_DISABLE_BIT = 0x4000, // disables dma ADC_ENABLE_BIT = 0x8000, // master adc enable};enum adc_control1_contents{ ADC_QUEUE_CONFIG_BIT = 0x1, // should be set for boards with > 16 channels CONVERT_POLARITY_BIT = 0x10, EOC_POLARITY_BIT = 0x20, SW_GATE_BIT = 0x40, // software gate of adc ADC_DITHER_BIT = 0x200, // turn on extra noise for dithering RETRIGGER_BIT = 0x800, ADC_LO_CHANNEL_4020_MASK = 0x300, ADC_HI_CHANNEL_4020_MASK = 0xc00, TWO_CHANNEL_4020_BITS = 0x1000, // two channel mode for 4020 FOUR_CHANNEL_4020_BITS = 0x2000, // four channel mode for 4020 CHANNEL_MODE_4020_MASK = 0x3000, ADC_MODE_MASK = 0xf000,};static inline uint16_t adc_lo_chan_4020_bits( unsigned int channel ){ return ( channel & 0x3 ) << 8;};static inline uint16_t adc_hi_chan_4020_bits( unsigned int channel ){ return ( channel & 0x3 ) << 10;};static inline uint16_t adc_mode_bits( unsigned int mode ){ return ( mode & 0xf ) << 12;};enum calibration_contents{ SELECT_8800_BIT = 0x1, SELECT_8402_64XX_BIT = 0x2, SELECT_1590_60XX_BIT = 0x2, CAL_EN_64XX_BIT = 0x40, // calibration enable for 64xx series SERIAL_DATA_IN_BIT = 0x80, SERIAL_CLOCK_BIT = 0x100, CAL_EN_60XX_BIT = 0x200, // calibration enable for 60xx series CAL_GAIN_BIT = 0x800,};/* calibration sources for 6025 are: * 0 : ground * 1 : 10V * 2 : 5V * 3 : 0.5V * 4 : 0.05V * 5 : ground * 6 : dac channel 0 * 7 : dac channel 1 */static inline uint16_t adc_src_bits( unsigned int source ){ return ( source & 0xf ) << 3;};static inline uint16_t adc_convert_chan_4020_bits( unsigned int channel ){ return ( channel & 0x3 ) << 8;};enum adc_queue_load_contents{ UNIP_BIT = 0x800, // unipolar/bipolar bit ADC_SE_DIFF_BIT = 0x1000, // single-ended/ differential bit ADC_COMMON_BIT = 0x2000, // non-referenced single-ended (common-mode input) QUEUE_EOSEQ_BIT = 0x4000, // queue end of sequence QUEUE_EOSCAN_BIT = 0x8000, // queue end of scan};static inline uint16_t adc_chan_bits( unsigned int channel ){ return channel & 0x3f;};enum dac_control0_contents{ DAC_ENABLE_BIT = 0x8000, // dac controller enable bit};enum dac_control1_contents{ DAC_OUTPUT_ENABLE_BIT = 0x80, // dac output enable bit};// bit definitions for read-only registersenum hw_status_contents{ DAC_UNDERRUN_BIT = 0x1, ADC_OVERRUN_BIT = 0x2, DAC_ACTIVE_BIT = 0x4, ADC_ACTIVE_BIT = 0x8, DAC_INTR_PENDING_BIT = 0x10, ADC_INTR_PENDING_BIT = 0x20, DAC_DONE_BIT = 0x40, ADC_DONE_BIT = 0x80, EXT_INTR_PENDING_BIT = 0x100, ADC_STOP_BIT = 0x200,};static inline uint16_t pipe_full_bits( uint16_t hw_status_bits ){ return ( hw_status_bits >> 10) & 0x3;};static inline unsigned int dma_chain_flag_bits( uint16_t prepost_bits ){ return ( prepost_bits >> 6 ) & 0x3;}static inline unsigned int adc_upper_read_ptr_code( uint16_t prepost_bits ){ return ( prepost_bits >> 12 ) & 0x3;}static inline unsigned int adc_upper_write_ptr_code( uint16_t prepost_bits ){ return ( prepost_bits >> 14 ) & 0x3;}// I2C addresses for 4020enum i2c_addresses{ RANGE_CAL_I2C_ADDR = 0x20, CALDAC0_I2C_ADDR = 0xc, CALDAC1_I2C_ADDR = 0xd,};enum range_cal_i2c_contents{ ADC_SRC_4020_MASK = 0x70, // bits that set what source the adc converter measures BNC_TRIG_THRESHOLD_0V_BIT = 0x80, // make bnc trig/ext clock threshold 0V instead of 2.5V};static inline uint8_t adc_src_4020_bits( unsigned int source ){ return ( source << 4 ) & ADC_SRC_4020_MASK;};static inline uint8_t attenuate_bit( unsigned int channel ){ // attenuate channel (+-5V input range) return 1 << ( channel & 0x3 );};// analog input ranges for 64xx boardsstatic comedi_lrange ai_ranges_64xx ={ 8, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), BIP_RANGE(1.25), UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2.5), UNI_RANGE(1.25) }};/* analog input ranges for 60xx boards */static comedi_lrange ai_ranges_60xx ={ 4, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(0.5), BIP_RANGE(0.05), }};/* analog input ranges for 6030, etc boards */static comedi_lrange ai_ranges_6030 ={ 14, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2), BIP_RANGE(1), BIP_RANGE(0.5), BIP_RANGE(0.2), BIP_RANGE(0.1), UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2), UNI_RANGE(1), UNI_RANGE(0.5), UNI_RANGE(0.2), UNI_RANGE(0.1), }};/* analog input ranges for 6052, etc boards */static comedi_lrange ai_ranges_6052 ={ 15, { BIP_RANGE(10), BIP_RANGE(5), BIP_RANGE(2.5), BIP_RANGE(1), BIP_RANGE(0.5), BIP_RANGE(0.25), BIP_RANGE(0.1), BIP_RANGE(0.05), UNI_RANGE(10), UNI_RANGE(5), UNI_RANGE(2), UNI_RANGE(1), UNI_RANGE(0.5), UNI_RANGE(0.2), UNI_RANGE(0.1), }};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -