📄 ni_labpc.c
字号:
range = CR_RANGE( cmd->chanlist[ 0 ] ); aref = CR_AREF( cmd->chanlist[ 0 ] ); for( i = 0; i < cmd->chanlist_len; i++ ) { switch( mode ) { case MODE_SINGLE_CHAN_INTERVAL: if( CR_CHAN( cmd->chanlist[ i ] ) != channel ) { comedi_error(dev, "channel scanning order specified in chanlist is not supported by hardware.\n"); return 1; } break; case MODE_MULT_CHAN_UP: if( CR_CHAN( cmd->chanlist[ i ] ) != i ) { comedi_error(dev, "channel scanning order specified in chanlist is not supported by hardware.\n"); return 1; } break; case MODE_MULT_CHAN_DOWN: if( CR_CHAN( cmd->chanlist[i] ) != cmd->chanlist_len - i - 1 ) { comedi_error(dev, "channel scanning order specified in chanlist is not supported by hardware.\n"); return 1; } break; default: rt_printk( "ni_labpc: bug! in chanlist check\n"); return 1; break; } if( CR_RANGE( cmd->chanlist[i] ) != range ) { comedi_error(dev, "entries in chanlist must all have the same range\n"); return 1; } if( CR_AREF( cmd->chanlist[i] ) != aref ) { comedi_error(dev, "entries in chanlist must all have the same reference\n"); return 1; } } return 0;}static int labpc_use_continuous_mode( const comedi_cmd *cmd ){ if( labpc_ai_scan_mode( cmd ) == MODE_SINGLE_CHAN ) return 1; if( cmd->scan_begin_src == TRIG_FOLLOW ) return 1; return 0;}static unsigned int labpc_ai_convert_period( const comedi_cmd *cmd ){ if( cmd->convert_src != TRIG_TIMER ) return 0; if( labpc_ai_scan_mode( cmd ) == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER ) return cmd->scan_begin_arg; return cmd->convert_arg;}static void labpc_set_ai_convert_period( comedi_cmd *cmd, unsigned int ns ){ if( cmd->convert_src != TRIG_TIMER ) return; if( labpc_ai_scan_mode( cmd ) == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER ) { cmd->scan_begin_arg = ns; if( cmd->convert_arg > cmd->scan_begin_arg ) cmd->convert_arg = cmd->scan_begin_arg; }else cmd->convert_arg = ns;}static unsigned int labpc_ai_scan_period( const comedi_cmd *cmd ){ if( cmd->scan_begin_src != TRIG_TIMER ) return 0; if( labpc_ai_scan_mode( cmd ) == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER ) return 0; return cmd->scan_begin_arg;}static void labpc_set_ai_scan_period( comedi_cmd *cmd, unsigned int ns ){ if( cmd->scan_begin_src != TRIG_TIMER ) return; if( labpc_ai_scan_mode( cmd ) == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER ) return; cmd->scan_begin_arg = ns;}static int labpc_ai_cmdtest(comedi_device *dev,comedi_subdevice *s,comedi_cmd *cmd){ int err = 0; int tmp, tmp2; int stop_mask; /* 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; cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT; if(!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; tmp = cmd->convert_src; cmd->convert_src &= TRIG_TIMER | TRIG_EXT; 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; stop_mask = TRIG_COUNT | TRIG_NONE; if(thisboard->register_layout == labpc_1200_layout) stop_mask |= TRIG_EXT; cmd->stop_src &= stop_mask; if(!cmd->stop_src || tmp!=cmd->stop_src) err++; if(err) return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ if(cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) err++; if(cmd->scan_begin_src != TRIG_TIMER && cmd->scan_begin_src != TRIG_FOLLOW && cmd->scan_begin_src != TRIG_EXT) err++; if(cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) err++; if(cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE) err++; // can't have external stop and start triggers at once if(cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT) err++; if(err)return 2; /* step 3: make sure arguments are trivially compatible */ if(cmd->start_arg == TRIG_NOW && cmd->start_arg != 0) { cmd->start_arg = 0; err++; } if(!cmd->chanlist_len) { err++; } if(cmd->scan_end_arg != cmd->chanlist_len) { cmd->scan_end_arg = cmd->chanlist_len; err++; } if(cmd->convert_src == TRIG_TIMER) { if(cmd->convert_arg < thisboard->ai_speed) { cmd->convert_arg = thisboard->ai_speed; err++; } } // make sure scan timing is not too fast if(cmd->scan_begin_src == TRIG_TIMER) { if(cmd->convert_src == TRIG_TIMER && cmd->scan_begin_arg < cmd->convert_arg * cmd->chanlist_len) { cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len; err++; } if(cmd->scan_begin_arg < thisboard->ai_speed * cmd->chanlist_len) { cmd->scan_begin_arg = thisboard->ai_speed * cmd->chanlist_len; err++; } } // stop source switch(cmd->stop_src) { 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; // TRIG_EXT doesn't care since it doesn't trigger off a numbered channel default: break; } if(err)return 3; /* step 4: fix up any arguments */ tmp = cmd->convert_arg; tmp2 = cmd->scan_begin_arg; labpc_adc_timing(dev, cmd); if(tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg) err++; if(err)return 4; if( labpc_ai_chanlist_invalid( dev, cmd ) ) return 5; return 0;}static int labpc_ai_cmd(comedi_device *dev, comedi_subdevice *s){ int channel, range, aref; unsigned long irq_flags; int ret; comedi_async *async = s->async; comedi_cmd *cmd = &async->cmd; enum transfer_type xfer; unsigned long flags; if(!dev->irq) { comedi_error(dev, "no irq assigned, cannot perform command"); return -1; } range = CR_RANGE(cmd->chanlist[0]); aref = CR_AREF(cmd->chanlist[0]); // make sure board is disabled before setting up aquisition comedi_spin_lock_irqsave( &dev->spinlock, flags ); devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); devpriv->command3_bits = 0; thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); // initialize software conversion count if(cmd->stop_src == TRIG_COUNT) { devpriv->count = cmd->stop_arg * cmd->chanlist_len; } // setup hardware conversion counter if(cmd->stop_src == TRIG_EXT) { // load counter a1 with count of 3 (pc+ manual says this is minimum allowed) using mode 0 ret = i8254_load(dev->iobase + COUNTER_A_BASE_REG, 1, 3, 0); if(ret < 0) { comedi_error(dev, "error loading counter a1"); return -1; } }else // otherwise, just put a1 in mode 0 with no count to set its output low thisboard->write_byte(INIT_A1_BITS, dev->iobase + COUNTER_A_CONTROL_REG); // figure out what method we will use to transfer data if(devpriv->dma_chan && // need a dma channel allocated // dma unsafe at RT priority, and too much setup time for TRIG_WAKE_EOS for (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 && // only available on the isa boards thisboard->bustype == isa_bustype) { xfer = isa_dma_transfer; }else if(thisboard->register_layout == labpc_1200_layout && // pc-plus has no fifo-half full interrupt // wake-end-of-scan should interrupt on fifo not empty (cmd->flags & TRIG_WAKE_EOS) == 0 && // make sure we are taking more than just a few points (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) { xfer = fifo_half_full_transfer; }else xfer = fifo_not_empty_transfer; devpriv->current_transfer = xfer; // setup command6 register for 1200 boards if(thisboard->register_layout == labpc_1200_layout) { // reference inputs to ground or common? if(aref != AREF_GROUND) devpriv->command6_bits |= ADC_COMMON_BIT; else devpriv->command6_bits &= ~ADC_COMMON_BIT; // bipolar or unipolar range? if(thisboard->ai_range_is_unipolar[range]) devpriv->command6_bits |= ADC_UNIP_BIT; else devpriv->command6_bits &= ~ADC_UNIP_BIT; // interrupt on fifo half full? if(xfer == fifo_half_full_transfer) devpriv->command6_bits |= ADC_FHF_INTR_EN_BIT; else devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT; // enable interrupt on counter a1 terminal count? if(cmd->stop_src == TRIG_EXT) devpriv->command6_bits |= A1_INTR_EN_BIT; else devpriv->command6_bits &= ~A1_INTR_EN_BIT; // are we scanning up or down through channels? if( labpc_ai_scan_mode( cmd ) == MODE_MULT_CHAN_UP ) devpriv->command6_bits |= ADC_SCAN_UP_BIT; else devpriv->command6_bits &= ~ADC_SCAN_UP_BIT; // write to register thisboard->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } /* setup channel list, etc (command1 register) */ devpriv->command1_bits = 0; if( labpc_ai_scan_mode( cmd ) == MODE_MULT_CHAN_UP ) channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); else channel = CR_CHAN(cmd->chanlist[0]); // munge channel bits for differential / scan disabled mode if( labpc_ai_scan_mode( cmd ) != MODE_SINGLE_CHAN && aref == AREF_DIFF ) channel *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(channel); devpriv->command1_bits |= thisboard->ai_range_code[range]; thisboard->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); // manual says to set scan enable bit on second pass if( labpc_ai_scan_mode( cmd ) == MODE_MULT_CHAN_UP || labpc_ai_scan_mode( cmd ) == MODE_MULT_CHAN_DOWN ) { devpriv->command1_bits |= ADC_SCAN_EN_BIT; /* need a brief delay before enabling scan, or scan list will get screwed when you switch * between scan up to scan down mode - dunno why */ comedi_udelay(1); thisboard->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); } // setup any external triggering/pacing (command4 register) devpriv->command4_bits = 0; if(cmd->convert_src != TRIG_EXT) devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; /* XXX should discard first scan when using interval scanning * since manual says it is not synced with scan clock */ if( labpc_use_continuous_mode( cmd ) == 0 ) { devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; if( cmd->scan_begin_src == TRIG_EXT ) devpriv->command4_bits |= EXT_SCAN_EN_BIT; } // single-ended/differential if(aref == AREF_DIFF) devpriv->command4_bits |= ADC_DIFF_BIT; thisboard->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); thisboard->write_byte( cmd->chanlist_len, dev->iobase + INTERVAL_COUNT_REG); // load count thisboard->write_byte(INTERVAL_LOAD_BITS, dev->iobase + INTERVAL_LOAD_REG); if(cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) { // set up pacing labpc_adc_timing(dev, cmd); // load counter b0 in mode 3 ret = i8254_load(dev->iobase + COUNTER_B_BASE_REG, 0, devpriv->divisor_b0, 3); if(ret < 0) { comedi_error(dev, "error loading counter b0"); return -1; } } // set up conversion pacing if( labpc_ai_convert_period( cmd ) ) { // load counter a0 in mode 2 ret = i8254_load(dev->iobase + COUNTER_A_BASE_REG, 0, devpriv->divisor_a0, 2); if(ret < 0) { comedi_error(dev, "error loading counter a0"); return -1; } }else thisboard->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG); // set up scan pacing if( labpc_ai_scan_period( cmd ) ) { // load counter b1 in mode 2 ret = i8254_load(dev->iobase + COUNTER_B_BASE_REG, 1, devpriv->divisor_b1, 2); if(ret < 0) { comedi_error(dev, "error loading counter b1"); return -1; } } labpc_clear_adc_fifo( dev ); // set up dma transfer if(xfer == isa_dma_transfer) { irq_flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma_chan); set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); // set appropriate size of transfer devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd); if(cmd->stop_src == TRIG_COUNT &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -