📄 cb_pcidas64.c
字号:
static int ai_config_insn( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int id = data[0]; switch( id ) { case INSN_CONFIG_ALT_SOURCE: return ai_config_calibration_source( dev, data ); break; case INSN_CONFIG_BLOCK_SIZE: return ai_config_block_size( dev, data ); break; case INSN_CONFIG_TIMER_1: return ai_config_master_clock( dev, data ); break; default: return -EINVAL; break; } return -EINVAL;}static int ai_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){ int err = 0; int tmp; unsigned int tmp_arg, tmp_arg2; int i; int aref; unsigned int triggers; /* step 1: make sure trigger sources are trivially valid */ tmp = cmd->start_src; cmd->start_src &= TRIG_NOW | TRIG_EXT; if(!cmd->start_src || tmp != cmd->start_src) err++; tmp = cmd->scan_begin_src; triggers = TRIG_TIMER; if(board(dev)->layout == LAYOUT_4020) triggers |= TRIG_OTHER; else triggers |= TRIG_FOLLOW; cmd->scan_begin_src &= triggers; if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; if(board(dev)->layout == LAYOUT_4020) triggers = TRIG_NOW | TRIG_OTHER; else triggers = TRIG_TIMER | TRIG_EXT; cmd->convert_src &= triggers; if(!cmd->convert_src || tmp != cmd->convert_src) err++; tmp = cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if(!cmd->scan_end_src || tmp != cmd->scan_end_src) err++; tmp=cmd->stop_src; cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; if(!cmd->stop_src || tmp != cmd->stop_src) err++; if(err) return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ // uniqueness check if(cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) err++; if(cmd->scan_begin_src != TRIG_TIMER && cmd->scan_begin_src != TRIG_OTHER && 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++; if(cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) err++; // compatibility check if(cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) 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) { 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++; } } } if(!cmd->chanlist_len) { cmd->chanlist_len = 1; err++; } if(cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } switch(cmd->stop_src) { case TRIG_EXT: break; case TRIG_COUNT: if(!cmd->stop_arg) { cmd->stop_arg = 1; err++; } break; case TRIG_NONE: if(cmd->stop_arg != 0) { cmd->stop_arg = 0; err++; } break; default: break; } if(err) return 3; /* step 4: fix up any arguments */ if(cmd->convert_src == TRIG_TIMER) { tmp_arg = cmd->convert_arg; tmp_arg2 = cmd->scan_begin_arg; check_adc_timing(cmd); if(tmp_arg != cmd->convert_arg) err++; if(tmp_arg2 != cmd->scan_begin_arg) err++; } if(err) return 4; // make sure user is doesn't change analog reference mid chanlist if(cmd->chanlist) { aref = CR_AREF(cmd->chanlist[0]); for(i = 1; i < cmd->chanlist_len; i++) { if(aref != CR_AREF(cmd->chanlist[i])) { comedi_error(dev, "all elements in chanlist must use the same analog reference"); err++; break; } } // check 4020 chanlist if( board(dev)->layout == LAYOUT_4020 ) { unsigned int first_channel = CR_CHAN( cmd->chanlist[0] ); for( i = 1; i < cmd->chanlist_len; i++ ) { if( CR_CHAN( cmd->chanlist[ i ] ) != first_channel + i ) { comedi_error( dev, "chanlist must use consecutive channels" ); err++; break; } } if( cmd->chanlist_len == 3 ) { comedi_error( dev, "chanlist cannot be 3 channels long, use 1, 2, or 4 channels" ); err++; } } } if(err) return 5; return 0;}static int use_hw_sample_counter( comedi_cmd *cmd ){ static const int max_hardware_count = 0xffffff;// disable for now until I work out a racereturn 0; if( cmd->stop_src == TRIG_COUNT && cmd->stop_arg <= max_hardware_count ) return 1; else return 0;}static void setup_sample_counters( comedi_device *dev, comedi_cmd *cmd ){ if( cmd->stop_src == TRIG_COUNT ) { // set software count priv(dev)->ai_count = cmd->stop_arg * cmd->chanlist_len; } // load hardware conversion counter if( use_hw_sample_counter( cmd ) ) { writew( cmd->stop_arg & 0xffff, priv(dev)->main_iobase + ADC_COUNT_LOWER_REG); writew( ( cmd->stop_arg >> 16 ) & 0xff, priv(dev)->main_iobase + ADC_COUNT_UPPER_REG); } else { writew( 1, priv(dev)->main_iobase + ADC_COUNT_LOWER_REG); }}static inline unsigned int dma_transfer_size( comedi_device *dev ){ unsigned int num_samples; num_samples = priv(dev)->ai_fifo_segment_length * board(dev)->ai_fifo->sample_packing_ratio; if( num_samples > DMA_BUFFER_SIZE / sizeof( uint16_t ) ) num_samples = DMA_BUFFER_SIZE / sizeof( uint16_t ); return num_samples;}static void disable_ai_pacing( comedi_device *dev ){ unsigned long flags; disable_ai_interrupts( dev ); /* disable pacing, triggering, etc */ writew( ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT, priv(dev)->main_iobase + ADC_CONTROL0_REG ); comedi_spin_lock_irqsave( &dev->spinlock, flags ); priv(dev)->adc_control1_bits &= ~SW_GATE_BIT; writew( priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG ); comedi_spin_unlock_irqrestore( &dev->spinlock, flags );}static void disable_ai_interrupts( comedi_device *dev ){ unsigned long flags; comedi_spin_lock_irqsave( &dev->spinlock, flags ); priv(dev)->intr_enable_bits &= ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT & ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK; writew( priv(dev)->intr_enable_bits, priv(dev)->main_iobase + INTR_ENABLE_REG ); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); DEBUG_PRINT( "intr enable bits 0x%x\n", priv(dev)->intr_enable_bits );}static void enable_ai_interrupts( comedi_device *dev, const comedi_cmd *cmd ){ uint32_t bits; unsigned long flags; bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT | EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT; // Use pio transfer and interrupt on end of conversion if TRIG_WAKE_EOS flag is set. if( cmd->flags & TRIG_WAKE_EOS ) { // 4020 doesn't support pio transfers except for fifo dregs if( board(dev)->layout != LAYOUT_4020 ) bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT; } comedi_spin_lock_irqsave( &dev->spinlock, flags ); priv(dev)->intr_enable_bits |= bits; writew( priv(dev)->intr_enable_bits, priv(dev)->main_iobase + INTR_ENABLE_REG ); DEBUG_PRINT( "intr enable bits 0x%x\n", priv(dev)->intr_enable_bits ); comedi_spin_unlock_irqrestore( &dev->spinlock, flags );}static uint32_t ai_convert_counter_6xxx( const comedi_device *dev, const comedi_cmd *cmd ){ // supposed to load counter with desired divisor minus 3 return cmd->convert_arg / TIMER_BASE - 3;}static uint32_t ai_scan_counter_6xxx( comedi_device *dev, comedi_cmd *cmd ){ // 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; } return 0;}static uint32_t ai_convert_counter_4020( comedi_device *dev, comedi_cmd *cmd ){ unsigned int divisor; 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; } // supposed to load counter with desired divisor minus 2 for 4020 return divisor / TIMER_BASE - 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 ) priv(dev)->hw_config_bits |= BNC_CLOCK_4020_BITS; else priv(dev)->hw_config_bits |= EXT_CLOCK_4020_BITS; }else { priv(dev)->hw_config_bits |= INTERNAL_CLOCK_4020_BITS; } writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG);}static void select_master_clock( comedi_device *dev, const comedi_cmd *cmd ){ switch( board(dev)->layout ) { case LAYOUT_4020: select_master_clock_4020( dev, cmd ); break; default: break; }}static void set_ai_pacing( comedi_device *dev, comedi_cmd *cmd ){ uint32_t convert_counter = 0, scan_counter = 0; check_adc_timing( cmd ); select_master_clock( dev, cmd ); if( board(dev)->layout == LAYOUT_4020 ) { convert_counter = ai_convert_counter_4020( dev, cmd ); }else { convert_counter = ai_convert_counter_6xxx( dev, cmd ); scan_counter = ai_scan_counter_6xxx( dev, cmd ); } // load lower 16 bits of convert interval writew( convert_counter & 0xffff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG ); DEBUG_PRINT("convert counter 0x%x\n", convert_counter ); // load upper 8 bits of convert interval writew( ( convert_counter >> 16 ) & 0xff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG ); // load lower 16 bits of scan delay writew( scan_counter & 0xffff, priv(dev)->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG ); // load upper 8 bits of scan delay writew( ( scan_counter >> 16 ) & 0xff, priv(dev)->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG ); DEBUG_PRINT("scan counter 0x%x\n", scan_counter );}static int ai_cmd(comedi_device *dev,comedi_subdevice *s){ comedi_async *async = s->async; comedi_cmd *cmd = &async->cmd; uint32_t bits; unsigned int i; unsigned long flags; disable_ai_pacing( dev ); // make sure internal calibration source is turned off writew(0, priv(dev)->main_iobase + CALIBRATION_REG); set_ai_pacing( dev, cmd ); setup_sample_counters( dev, cmd ); if(board(dev)->layout != LAYOUT_4020) { // use external queue priv(dev)->hw_config_bits |= EXT_QUEUE_BIT; writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG); /* XXX cannot write to queue fifo while dac fifo is being written to * ( need spinlock, or try to use internal queue instead */ // clear queue pointer writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG); // load external queue for(i = 0; i < cmd->chanlist_len; i++) { bits = 0; // set channel bits |= adc_chan_bits( CR_CHAN( cmd->chanlist[i] ) ); // set gain bits |= ai_range_bits_6xxx( dev, CR_RANGE( cmd->chanlist[i] ) ); // set single-ended / differential if( ( board(dev)->layout == LAYOUT_64XX && CR_AREF(cmd->chanlist[i]) != AREF_DIFF ) || ( board(dev)->layout == LAYOUT_60XX && CR_AREF(cmd->chanlist[i]) == AREF_DIFF ) ) bits |= ADC_SE_DIFF_BIT; if(CR_AREF(cmd->chanlist[i]) == AREF_COMMON) bits |= ADC_COMMON_BIT; // mark end of queue if(i == cmd->chanlist_len - 1) bits |= QUEUE_EOSCAN_BIT | QUEUE_EOSEQ_BIT; writew(bits, priv(dev)->main_iobase + ADC_QUEUE_FIFO_REG); } // prime queue holding register writew(0, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); }else { uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits; priv(dev)->i2c_cal_range_bits &= ~ADC_SR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -