📄 ni_atmio16d.c
字号:
outw(0x1025, dev->iobase+AM9513A_DATA_REG); outw(0xFF0C, dev->iobase+AM9513A_COM_REG); if(sample_count < 65536) { /* use only Counter 4 */ outw(sample_count, dev->iobase+AM9513A_DATA_REG); outw(0xFF48, dev->iobase+AM9513A_COM_REG); outw(0xFFF4, dev->iobase+AM9513A_COM_REG); outw(0xFF28, dev->iobase+AM9513A_COM_REG); devpriv->com_reg_1_state &= ~COMREG1_1632CNT; outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1); } else { /* Counter 4 and 5 are needed */ if( (tmp=sample_count&0xFFFF) ) { outw(tmp-1, dev->iobase+AM9513A_DATA_REG); } else { outw(0xFFFF, dev->iobase+AM9513A_DATA_REG); } outw(0xFF48, dev->iobase+AM9513A_COM_REG); outw(0, dev->iobase+AM9513A_DATA_REG); outw(0xFF28, dev->iobase+AM9513A_COM_REG); outw(0xFF05, dev->iobase+AM9513A_COM_REG); outw(0x25, dev->iobase+AM9513A_DATA_REG); outw(0xFF0D, dev->iobase+AM9513A_COM_REG); tmp=sample_count&0xFFFF; if( (tmp == 0) || (tmp == 1) ) { outw( (sample_count>>16)&0xFFFF, dev->iobase+AM9513A_DATA_REG); } else { outw( ((sample_count>>16)&0xFFFF)+1, dev->iobase+AM9513A_DATA_REG); } outw(0xFF70, dev->iobase+AM9513A_COM_REG); devpriv->com_reg_1_state |= COMREG1_1632CNT; outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1); } /* Program the scan interval timer ONLY IF SCANNING IS ENABLED */ /* Figure out which clock to use then get an * appropriate timer value */ if(cmd->chanlist_len > 1) { if(cmd->scan_begin_arg<65536000) { base_clock = CLOCK_1_MHZ; timer = cmd->scan_begin_arg/1000; } else if(cmd->scan_begin_arg<655360000) { base_clock = CLOCK_100_KHZ; timer = cmd->scan_begin_arg/10000; } else if(cmd->scan_begin_arg<0xffffffff /* 6553600000 */ ) { base_clock = CLOCK_10_KHZ; timer = cmd->scan_begin_arg/100000; } else if(cmd->scan_begin_arg<0xffffffff /* 65536000000 */ ) { base_clock = CLOCK_1_KHZ; timer = cmd->scan_begin_arg/1000000; } outw(0xFF02, dev->iobase+AM9513A_COM_REG); outw(base_clock, dev->iobase+AM9513A_DATA_REG); outw(0xFF0A, dev->iobase+AM9513A_COM_REG); outw(0x2, dev->iobase+AM9513A_DATA_REG); outw(0xFF42, dev->iobase+AM9513A_COM_REG); outw(0xFFF2, dev->iobase+AM9513A_COM_REG); outw(timer, dev->iobase+AM9513A_DATA_REG); outw(0xFF22, dev->iobase+AM9513A_COM_REG); } /* Clear the A/D FIFO and reset the MUX counter */ outw(0, dev->iobase+AD_CLEAR_REG); outw(0, dev->iobase+MUX_CNTR_REG); outw(0, dev->iobase+INT2CLR_REG); /* enable this acquisition operation */ devpriv->com_reg_1_state |= COMREG1_DAQEN; outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1); /* enable interrupts for conversion completion */ devpriv->com_reg_1_state |= COMREG1_CONVINTEN; devpriv->com_reg_2_state |= COMREG2_INTEN; outw(devpriv->com_reg_1_state, dev->iobase+COM_REG_1); outw(devpriv->com_reg_2_state, dev->iobase+COM_REG_2); /* apply a trigger. this starts the counters! */ outw(0, dev->iobase+START_DAQ_REG); return 0;}/* This will cancel a running acquisition operation */static int atmio16d_ai_cancel(comedi_device *dev, comedi_subdevice *s){ reset_atmio16d(dev); return 0;}/* Mode 0 is used to get a single conversion on demand */static int atmio16d_ai_insn_read(comedi_device * dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int i, t; int chan; int gain; int status; #ifdef DEBUG1 printk("atmio16d_ai_insn_read\n");#endif chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); /* reset the Analog input circuitry */ //outw( 0, dev->iobase+AD_CLEAR_REG ); /* reset the Analog Input MUX Counter to 0 */ //outw( 0, dev->iobase+MUX_CNTR_REG ); /* set the Input MUX gain */ outw( chan|(gain<<6), dev->iobase+MUX_GAIN_REG); for(i=0 ; i < insn->n ; i++) { /* start the conversion */ outw(0, dev->iobase+START_CONVERT_REG); /* wait for it to finish */ for(t = 0; t < ATMIO16D_TIMEOUT; t++) { /* check conversion status */ status=inw(dev->iobase+STAT_REG);#ifdef DEBUG1 printk("status=%x\n",status);#endif if( status&STAT_AD_CONVAVAIL ) { /* read the data now */ data[i] = inw( dev->iobase+AD_FIFO_REG ); /* change to two's complement if need be */ if( devpriv->adc_coding == adc_2comp ) { data[i] ^= 0x800; } break; } if( status&STAT_AD_OVERFLOW ){ printk("atmio16d: a/d FIFO overflow\n"); outw(0,dev->iobase+AD_CLEAR_REG); return -ETIME; } } /* end waiting, now check if it timed out */ if( t == ATMIO16D_TIMEOUT ){ rt_printk("atmio16d: timeout\n"); return -ETIME; } } return i;}static int atmio16d_ao_insn_read(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int i;#ifdef DEBUG1 printk("atmio16d_ao_insn_read\n");#endif for(i=0;i<insn->n;i++){ data[i]=devpriv->ao_readback[CR_CHAN(insn->chanspec)]; } return i;}static int atmio16d_ao_insn_write(comedi_device * dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int i; int chan; int d;#ifdef DEBUG1 printk("atmio16d_ao_insn_write\n");#endif chan=CR_CHAN(insn->chanspec); for(i=0; i < insn->n; i++) { d = data[i]; switch(chan){ case 0: if (devpriv->dac0_coding == dac_2comp) { d ^= 0x800; } outw(d, dev->iobase + DAC0_REG); break; case 1: if (devpriv->dac1_coding == dac_2comp) { d ^= 0x800; } outw(d, dev->iobase + DAC1_REG); break; default: return -EINVAL; } devpriv->ao_readback[chan] = data[i]; } return i;}static int atmio16d_dio_insn_bits(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ if(insn->n!=2)return -EINVAL; if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]|data[1]); outw(s->state, dev->iobase+MIO_16_DIG_OUT_REG ); } data[1] = inw(dev->iobase+MIO_16_DIG_IN_REG); return 2;}static int atmio16d_dio_insn_config(comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data){ int i; int mask; for(i=0;i<insn->n;i++){ mask=(CR_CHAN(insn->chanspec)<4)?0x0f:0xf0; s->io_bits &= ~mask; if(data[i])s->io_bits |= mask; } devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0|COMREG2_DOUTEN1); if(s->io_bits&0x0f) devpriv->com_reg_2_state |= COMREG2_DOUTEN0; if(s->io_bits&0xf0) devpriv->com_reg_2_state |= COMREG2_DOUTEN1; outw(devpriv->com_reg_2_state, dev->iobase+COM_REG_2); return i;}/* options[0] - I/O port options[1] - MIO irq 0 == no irq N == irq N {3,4,5,6,7,9,10,11,12,14,15} options[2] - DIO irq 0 == no irq N == irq N {3,4,5,6,7,9} options[3] - DMA1 channel 0 == no DMA N == DMA N {5,6,7} options[4] - DMA2 channel 0 == no DMA N == DMA N {5,6,7} options[5] - a/d mux 0=differential, 1=single options[6] - a/d range 0=bipolar10, 1=bipolar5, 2=unipolar10 options[7] - dac0 range 0=bipolar, 1=unipolar options[8] - dac0 reference 0=internal, 1=external options[9] - dac0 coding 0=2's comp, 1=straight binary options[10] - dac1 range options[11] - dac1 reference options[12] - dac1 coding */static int atmio16d_attach(comedi_device * dev, comedi_devconfig * it){ int irq; int iobase; int ret; comedi_subdevice *s; /* make sure the address range is free and allocate it */ iobase = it->options[0]; printk("comedi%d: atmio16d: 0x%04x ", dev->minor, iobase); if (check_region(iobase, ATMIO16D_SIZE) < 0) { printk("I/O port conflict\n"); return -EIO; } request_region(iobase, ATMIO16D_SIZE, "ni_atmio16d"); dev->iobase = iobase; /* board name */ dev->board_name = boardtype->name; if((ret=alloc_subdevices(dev, 4))<0) return ret; if((ret=alloc_private(dev,sizeof(atmio16d_private)))<0) return ret; /* reset the atmio16d hardware */ reset_atmio16d(dev); /* check if our interrupt is available and get it */ irq=it->options[1]; if(irq>0){ if((ret=comedi_request_irq(irq,atmio16d_interrupt, 0, "atmio16d", dev))<0) return ret; dev->irq=irq; printk("( irq = %d )\n",irq); } else if(irq == 0){ printk("( no irq )"); } /* set device options */ devpriv->adc_mux = it->options[5]; devpriv->adc_range = it->options[6]; devpriv->dac0_range = it->options[7]; devpriv->dac0_reference = it->options[8]; devpriv->dac0_coding = it->options[9]; devpriv->dac1_range = it->options[10]; devpriv->dac1_reference = it->options[11]; devpriv->dac1_coding = it->options[12]; /* setup sub-devices */ s=dev->subdevices+0; dev->read_subdev = s; /* ai subdevice */ s->type=COMEDI_SUBD_AI; s->subdev_flags=SDF_READABLE|SDF_GROUND; s->n_chan=(devpriv->adc_mux? 16 : 8); s->len_chanlist=16; s->insn_read = atmio16d_ai_insn_read; s->do_cmdtest=atmio16d_ai_cmdtest; s->do_cmd=atmio16d_ai_cmd; s->cancel=atmio16d_ai_cancel; s->maxdata=0xfff; /* 4095 decimal */ switch (devpriv->adc_range) { case adc_bipolar10: s->range_table = &range_atmio16d_ai_10_bipolar; break; case adc_bipolar5: s->range_table = &range_atmio16d_ai_5_bipolar; break; case adc_unipolar10: s->range_table = &range_atmio16d_ai_unipolar; break; } /* ao subdevice */ s++; s->type=COMEDI_SUBD_AO; s->subdev_flags=SDF_WRITABLE; s->n_chan=2; s->insn_read=atmio16d_ao_insn_read; s->insn_write=atmio16d_ao_insn_write; s->maxdata=0xfff; /* 4095 decimal */ s->range_table_list=devpriv->ao_range_type_list; switch (devpriv->dac0_range) { case dac_bipolar: devpriv->ao_range_type_list[0] = &range_bipolar10; break; case dac_unipolar: devpriv->ao_range_type_list[0] = &range_unipolar10; break; } switch (devpriv->dac1_range) { case dac_bipolar: devpriv->ao_range_type_list[1] = &range_bipolar10; break; case dac_unipolar: devpriv->ao_range_type_list[1] = &range_unipolar10; break; } /* Digital I/O */ s++; s->type=COMEDI_SUBD_DIO; s->subdev_flags=SDF_WRITABLE|SDF_READABLE; s->n_chan=8; s->insn_bits = atmio16d_dio_insn_bits; s->insn_config = atmio16d_dio_insn_config; s->maxdata=1; s->range_table=&range_digital; /* 8255 subdevice */ s++; if(boardtype->has_8255){ subdev_8255_init(dev,s,NULL,(unsigned long)dev->iobase); }else{ s->type=COMEDI_SUBD_UNUSED; }/* don't yet know how to deal with counter/timers */#if 0 s++; /* do */ s->type=COMEDI_SUBD_TIMER; s->n_chan=0; s->maxdata=0#endif printk("\n"); return 0;}static int atmio16d_detach(comedi_device * dev){ printk("comedi%d: atmio16d: remove\n", dev->minor); if(dev->subdevices && boardtype->has_8255) subdev_8255_cleanup(dev,dev->subdevices + 3); if(dev->irq) comedi_free_irq(dev->irq,dev); reset_atmio16d(dev); if(dev->iobase) release_region(dev->iobase, ATMIO16D_SIZE); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -