📄 ni_labpc.c
字号:
devpriv->count * sample_size < devpriv->dma_transfer_size) { devpriv->dma_transfer_size = devpriv->count * sample_size; } set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(irq_flags); // enable board's dma devpriv->command3_bits |= DMA_EN_BIT | DMATC_INTR_EN_BIT; }else devpriv->command3_bits &= ~DMA_EN_BIT & ~DMATC_INTR_EN_BIT; // enable error interrupts devpriv->command3_bits |= ERR_INTR_EN_BIT; // enable fifo not empty interrupt? if(xfer == fifo_not_empty_transfer) devpriv->command3_bits |= ADC_FNE_INTR_EN_BIT; else devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT; thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); // startup aquisition // command2 reg // use 2 cascaded counters for pacing comedi_spin_lock_irqsave( &dev->spinlock, flags ); devpriv->command2_bits |= CASCADE_BIT; switch(cmd->start_src) { case TRIG_EXT: devpriv->command2_bits |= HWTRIG_BIT; devpriv->command2_bits &= ~PRETRIG_BIT & ~SWTRIG_BIT; break; case TRIG_NOW: devpriv->command2_bits |= SWTRIG_BIT; devpriv->command2_bits &= ~PRETRIG_BIT & ~HWTRIG_BIT; break; default: comedi_error(dev, "bug with start_src"); return -1; break; } switch(cmd->stop_src) { case TRIG_EXT: devpriv->command2_bits |= HWTRIG_BIT | PRETRIG_BIT; break; case TRIG_COUNT: case TRIG_NONE: break; default: comedi_error(dev, "bug with stop_src"); return -1; } thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); return 0;}/* interrupt service routine */static void labpc_interrupt(int irq, void *d, struct pt_regs *regs){ comedi_device *dev = d; comedi_subdevice *s = dev->read_subdev; comedi_async *async; comedi_cmd *cmd; if(dev->attached == 0) { comedi_error(dev, "premature interrupt"); return; } async = s->async; cmd = &async->cmd; async->events = 0; // read board status devpriv->status1_bits = thisboard->read_byte(dev->iobase + STATUS1_REG); if(thisboard->register_layout == labpc_1200_layout) devpriv->status2_bits = thisboard->read_byte(dev->iobase + STATUS2_REG); if((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT | OVERRUN_BIT | DATA_AVAIL_BIT)) == 0 && (devpriv->status2_bits & A1_TC_BIT) == 0 && (devpriv->status2_bits & FNHF_BIT)) { return; } if(devpriv->status1_bits & OVERRUN_BIT) { // clear error interrupt thisboard->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; comedi_event(dev, s, async->events); comedi_error(dev, "overrun"); return; } if(devpriv->current_transfer == isa_dma_transfer) { // if a dma terminal count of external stop trigger has occurred if(devpriv->status1_bits & DMATC_BIT || (thisboard->register_layout == labpc_1200_layout && devpriv->status2_bits & A1_TC_BIT)) { handle_isa_dma(dev); } }else labpc_drain_fifo(dev); if(devpriv->status1_bits & TIMER_BIT) { comedi_error(dev, "handled timer interrupt?"); // clear it thisboard->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG); } if(devpriv->status1_bits & OVERFLOW_BIT) { // clear error interrupt thisboard->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; comedi_error(dev, "overflow"); return; } // handle external stop trigger if(cmd->stop_src == TRIG_EXT) { if(devpriv->status2_bits & A1_TC_BIT) { labpc_drain_dregs(dev); labpc_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } /* TRIG_COUNT end of acquisition */ if(cmd->stop_src == TRIG_COUNT) { if(devpriv->count == 0) { labpc_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } comedi_event(dev, s, async->events);}// read all available samples from ai fifostatic int labpc_drain_fifo(comedi_device *dev){ unsigned int lsb, msb; sampl_t data; comedi_async *async = dev->read_subdev->async; const int timeout = 10000; unsigned int i; devpriv->status1_bits = thisboard->read_byte(dev->iobase + STATUS1_REG); for(i = 0; (devpriv->status1_bits & DATA_AVAIL_BIT) && i < timeout; i++) { // quit if we have all the data we want if(async->cmd.stop_src == TRIG_COUNT) { if(devpriv->count == 0) break; devpriv->count--; } lsb = thisboard->read_byte(dev->iobase + ADC_FIFO_REG); msb = thisboard->read_byte(dev->iobase + ADC_FIFO_REG); data = (msb << 8) | lsb; cfc_write_to_buffer( dev->read_subdev, data ); devpriv->status1_bits = thisboard->read_byte(dev->iobase + STATUS1_REG); } if(i == timeout) { comedi_error(dev, "ai timeout, fifo never empties"); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; return -1; } return 0;}static void labpc_drain_dma(comedi_device *dev){ comedi_subdevice *s = dev->read_subdev; comedi_async *async = s->async; int status; unsigned long flags; unsigned int max_points, num_points, residue, leftover; int i; status = devpriv->status1_bits; 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); // figure out how many points to read max_points = devpriv->dma_transfer_size / sample_size; /* residue is the number of points left to be done on the dma * transfer. It should always be zero at this point unless * the stop_src is set to external triggering. */ residue = get_dma_residue(devpriv->dma_chan) / sample_size; num_points = max_points - residue; if(devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT) num_points = devpriv->count; // figure out how many points will be stored next time leftover = 0; if(async->cmd.stop_src != TRIG_COUNT) { leftover = devpriv->dma_transfer_size / sample_size; }else if(devpriv->count > num_points) { leftover = devpriv->count - num_points; if(leftover > max_points) leftover = max_points; } /* write data to comedi buffer */ for( i = 0; i < num_points; i++) { cfc_write_to_buffer( s, devpriv->dma_buffer[i] ); } if(async->cmd.stop_src == TRIG_COUNT) devpriv->count -= num_points; // set address and count for next transfer set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); set_dma_count(devpriv->dma_chan, leftover * sample_size); release_dma_lock(flags); async->events |= COMEDI_CB_BLOCK;}static void handle_isa_dma(comedi_device *dev){ labpc_drain_dma(dev); enable_dma(devpriv->dma_chan); // clear dma tc interrupt thisboard->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);}/* makes sure all data aquired by board is transfered to comedi (used * when aquisition is terminated by stop_src == TRIG_EXT). */static void labpc_drain_dregs(comedi_device *dev){ if(devpriv->current_transfer == isa_dma_transfer) labpc_drain_dma(dev); labpc_drain_fifo(dev);}static int labpc_ai_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int i, n; int chan, range; int lsb, msb; int timeout = 1000; unsigned long flags; // disable timed conversions 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 ); // disable interrupt generation and dma devpriv->command3_bits = 0; thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); /* set gain and channel */ devpriv->command1_bits = 0; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); devpriv->command1_bits |= thisboard->ai_range_code[range]; // munge channel bits for differential/scan disabled mode if(CR_AREF(insn->chanspec) == AREF_DIFF) chan *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(chan); thisboard->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); // setup command6 register for 1200 boards if(thisboard->register_layout == labpc_1200_layout) { // reference inputs to ground or common? if(CR_AREF(insn->chanspec) != 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; // don't interrupt on fifo half full devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT; // don't enable interrupt on counter a1 terminal count? devpriv->command6_bits &= ~A1_INTR_EN_BIT; // write to register thisboard->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } // setup command4 register devpriv->command4_bits = 0; devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; // single-ended/differential if(CR_AREF(insn->chanspec) == AREF_DIFF) devpriv->command4_bits |= ADC_DIFF_BIT; thisboard->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); // initialize pacer counter output to make sure it doesn't cause any problems thisboard->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG); labpc_clear_adc_fifo( dev ); for(n = 0; n < insn->n; n++) { /* trigger conversion */ thisboard->write_byte(0x1, dev->iobase + ADC_CONVERT_REG); for(i = 0; i < timeout; i++) { if(thisboard->read_byte(dev->iobase + STATUS1_REG) & DATA_AVAIL_BIT) break; comedi_udelay( 1 ); } if(i == timeout) { comedi_error(dev, "timeout"); return -ETIME; } lsb = thisboard->read_byte(dev->iobase + ADC_FIFO_REG); msb = thisboard->read_byte(dev->iobase + ADC_FIFO_REG); data[n] = (msb << 8) | lsb; } return n;}// analog output insnstatic int labpc_ao_winsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int channel, range; unsigned long flags; int lsb, msb; channel = CR_CHAN(insn->chanspec); // turn off pacing of analog output channel /* note: hardware bug in daqcard-1200 means pacing cannot * be independently enabled/disabled for its the two channels */ comedi_spin_lock_irqsave( &dev->spinlock, flags ); devpriv->command2_bits &= ~DAC_PACED_BIT(channel); thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); // set range if(thisboard->register_layout == labpc_1200_layout) { range = CR_RANGE(insn->chanspec); if(range & AO_RANGE_IS_UNIPOLAR) devpriv->command6_bits |= DAC_UNIP_BIT(channel); else devpriv->command6_bits &= ~DAC_UNIP_BIT(channel); // write to register thisboard->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } // send data lsb = data[0] & 0xff; msb = (data[0] >> 8 ) & 0xff; thisboard->write_byte(lsb, dev->iobase + DAC_LSB_REG(channel)); thisboard->write_byte(msb, dev->iobase + DAC_MSB_REG(channel)); // remember value for readback devpriv->ao_value[channel] = data[0]; return 1;}// analog output readback insnstatic int labpc_ao_rinsn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; return 1;}static int labpc_calib_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)]; return 1;}static int labpc_calib_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int channel = CR_CHAN(insn->chanspec); write_caldac( dev, channel, data[ 0 ] ); return 1;}static int labpc_eeprom_read_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)]; return 1;}static int labpc_eeprom_write_insn(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int channel = CR_CHAN(insn->chanspec); int ret; // only allow writes to user area of eeprom if(channel < 16 || channel > 127) { printk("eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)"); return -EINVAL; } ret = labpc_eeprom_write(dev, channel, data[0]); if(ret < 0) return ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -