RTXI 1.3
comedi/comedi/drivers/adq12b.c
Go to the documentation of this file.
00001 /*
00002     comedi/drivers/adq12b.c
00003     driver for MicroAxial ADQ12-B data acquisition and control card
00004 
00005     COMEDI - Linux Control and Measurement Device Interface
00006     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022 */
00023 /*
00024 Driver: adq12b
00025 Description: driver for MicroAxial ADQ12-B data acquisition and control card
00026 Devices: [MicroAxial] ADQ12-B (adq12b)
00027 Author: jeremy theler <thelerg@ib.cnea.gov.ar>
00028 Updated: Thu, 21 Feb 2008 02:56:27 -0300
00029 Status: works
00030 
00031 Driver for the acquisition card ADQ12-B (without any add-on).
00032 
00033  - Analog input is subdevice 0 (16 channels single-ended or 8 differential)
00034  - Digital input is subdevice 1 (5 channels)
00035  - Digital output is subdevice 1 (8 channels)
00036  - The PACER is not supported in this version
00037 
00038 If you do not specify any options, they will default to
00039 
00040   # comedi_config /dev/comedi0 adq12b 0x300,0,0
00041 
00042   option 1: I/O base address. The following table is provided as a help
00043    of the hardware jumpers.
00044 
00045          address            jumper JADR
00046           0x300                 1 (factory default)
00047           0x320                 2
00048           0x340                 3
00049           0x360                 4
00050           0x380                 5
00051           0x3A0                 6
00052 
00053   option 2: unipolar/bipolar ADC selection: 0 -> bipolar, 1 -> unipolar
00054 
00055         selection         comedi_config option            JUB
00056          bipolar                0                         2-3 (factory default)
00057          unipolar               1                         1-2
00058 
00059   option 3: single-ended/differential AI selection: 0 -> SE, 1 -> differential
00060 
00061         selection         comedi_config option     JCHA    JCHB
00062        single-ended             0                  1-2     1-2 (factory default) 
00063        differential             1                  2-3     2-3
00064 
00065 
00066    written by jeremy theler <thelerg@ib.cnea.gov.ar>
00067 
00068    instituto balseiro
00069    comision nacional de energia atomica
00070    universidad nacional de cuyo
00071    argentina
00072 
00073    21-feb-2008
00074      + changed supported devices string (missused the [] and ())
00075 
00076    13-oct-2007
00077      + first try
00078 
00079 
00080 */
00081 
00082 #include <linux/comedidev.h>
00083 
00084 // address scheme (page 2.17 of the manual)
00085 #define ADQ12B_SIZE     16
00086 
00087 #define ADQ12B_CTREG    0x00
00088 #define ADQ12B_STINR    0x00
00089 #define ADQ12B_OUTBR    0x04
00090 #define ADQ12B_ADLOW    0x08
00091 #define ADQ12B_ADHIG    0x09
00092 #define ADQ12B_CONT0    0x0c
00093 #define ADQ12B_CONT1    0x0d
00094 #define ADQ12B_CONT2    0x0e
00095 #define ADQ12B_COWORD   0x0f
00096 
00097 // mask of the bit at STINR to check end of conversion
00098 #define ADQ12B_EOC     0x20
00099 
00100 #define TIMEOUT        20
00101 
00102 // available ranges through the PGA gains
00103 static const comedi_lrange range_adq12b_ai_bipolar = { 4, {
00104         BIP_RANGE( 5 ),
00105         BIP_RANGE( 2 ),
00106         BIP_RANGE( 1 ),
00107         BIP_RANGE( 0.5 )
00108 }};
00109 
00110 static const comedi_lrange range_adq12b_ai_unipolar = { 4, {
00111         UNI_RANGE( 5 ),
00112         UNI_RANGE( 2 ),
00113         UNI_RANGE( 1 ),
00114         UNI_RANGE( 0.5 )
00115 }};
00116 
00117 
00118 
00119 typedef struct adq12b_board_struct{
00120         const char *name;
00121         int ai_se_chans;
00122         int ai_diff_chans;      
00123         int ai_bits;
00124         int di_chans;
00125         int do_chans;
00126 }adq12b_board;
00127 
00128 static const adq12b_board adq12b_boards[] = {
00129         {
00130         name:           "adq12b",
00131         ai_se_chans:    16,
00132         ai_diff_chans:  8,      
00133         ai_bits:        12,
00134         di_chans:       5,
00135         do_chans:       8
00136         }
00137 // potentially, more adq-based deviced will be added
00138 /*,
00139         name:           "adq12b",
00140         ai_chans:       16,  // this is just for reference, hardcoded again later
00141         ai_bits:        12,
00142         di_chans:       8,
00143         do_chans:       5
00144         }*/
00145 };
00146 
00147 #define thisboard ((const adq12b_board *)dev->board_ptr)
00148 
00149 typedef struct{
00150         int unipolar;          /* option 2 of comedi_config (1 is iobase) */
00151         int differential;      /* option 3 of comedi_config */
00152         int last_channel;
00153         int last_range;
00154         lsampl_t digital_state;
00155  }adq12b_private;
00156 
00157 #define devpriv ((adq12b_private *)dev->private)
00158 
00159 /*
00160  * The comedi_driver structure tells the Comedi core module
00161  * which functions to call to configure/deconfigure (attach/detach)
00162  * the board, and also about the kernel module that contains
00163  * the device code.
00164  */
00165 static int adq12b_attach(comedi_device *dev,comedi_devconfig *it);
00166 static int adq12b_detach(comedi_device *dev);
00167 static comedi_driver driver_adq12b={
00168         driver_name:    "adq12b",
00169         module:         THIS_MODULE,
00170         attach:         adq12b_attach,
00171         detach:         adq12b_detach,
00172         board_name:     &adq12b_boards[0].name,
00173         offset:         sizeof(adq12b_board),
00174         num_names:      sizeof(adq12b_boards) / sizeof(adq12b_board),
00175 };
00176 
00177 static int adq12b_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data);
00178 static int adq12b_di_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);
00179 static int adq12b_do_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data);
00180 
00181 /*
00182  * Attach is called by the Comedi core to configure the driver
00183  * for a particular board.  If you specified a board_name array
00184  * in the driver structure, dev->board_ptr contains that
00185  * address.
00186  */
00187 static int adq12b_attach(comedi_device *dev,comedi_devconfig *it)
00188 {
00189         comedi_subdevice *s;
00190         unsigned long iobase;
00191         int unipolar, differential;
00192 
00193         iobase = it->options[0];
00194         unipolar = it->options[1];
00195         differential = it->options[2];
00196 
00197         printk("comedi%d: adq12b called with options base=0x%03lx, %s and %s\n",dev->minor, iobase, (unipolar==1)?"unipolar":"bipolar", (differential==1)?"differential":"single-ended");
00198 
00199         /* if no address was specified, try the default 0x300 */
00200         if (iobase == 0) {
00201           printk("comedi%d: adq12b warning: I/O base address not specified. Trying the default 0x300.\n", dev->minor);
00202           iobase = 0x300;
00203         }
00204 
00205         printk("comedi%d: adq12b: 0x%04lx ", dev->minor, iobase);
00206         if (!request_region(iobase, ADQ12B_SIZE, "adq12b")) {
00207           printk("I/O port conflict\n");
00208           return -EIO;
00209         }
00210         dev->iobase = iobase;
00211 
00212 /*
00213  * Initialize dev->board_name.  Note that we can use the "thisboard"
00214  * macro now, since we just initialized it in the last line.
00215  */
00216         dev->board_name = thisboard->name;
00217 
00218 /*
00219  * Allocate the private structure area.  alloc_private() is a
00220  * convenient macro defined in comedidev.h.
00221  */
00222         if(alloc_private(dev, sizeof(adq12b_private)) < 0)
00223           return -ENOMEM;
00224 
00225 /* fill in devpriv structure */
00226         devpriv->unipolar = unipolar;
00227         devpriv->differential = differential;
00228         devpriv->digital_state = 0;
00229 /* initialize channel and range to -1 so we make sure we always write
00230    at least once to the CTREG in the instruction */
00231         devpriv->last_channel = -1;
00232         devpriv->last_range = -1;
00233 
00234 
00235 /*
00236  * Allocate the subdevice structures.  alloc_subdevice() is a
00237  * convenient macro defined in comedidev.h.
00238  */
00239         if(alloc_subdevices(dev, 3)<0)
00240            return -ENOMEM;
00241 
00242         s = dev->subdevices+0;
00243         /* analog input subdevice */
00244         s->type = COMEDI_SUBD_AI;
00245         if (differential) {
00246           s->subdev_flags = SDF_READABLE|SDF_GROUND|SDF_DIFF;
00247           s->n_chan = thisboard->ai_diff_chans;
00248         } else {
00249           s->subdev_flags = SDF_READABLE|SDF_GROUND;
00250           s->n_chan = thisboard->ai_se_chans;
00251         }
00252 
00253         if (unipolar) {
00254           s->range_table = &range_adq12b_ai_unipolar;
00255         } else {
00256           s->range_table = &range_adq12b_ai_bipolar;
00257         }
00258 
00259         s->maxdata = (1 << thisboard->ai_bits)-1;
00260 
00261 
00262         s->len_chanlist = 4;  /* This is the maximum chanlist length that
00263                                  the board can handle */
00264         s->insn_read = adq12b_ai_rinsn;
00265 
00266 
00267         s = dev->subdevices+1;
00268         /* digital input subdevice */
00269         s->type = COMEDI_SUBD_DI;
00270         s->subdev_flags = SDF_READABLE;
00271         s->n_chan=thisboard->di_chans;
00272         s->maxdata = 1;
00273         s->range_table = &range_digital;
00274         s->insn_bits = adq12b_di_insn_bits;
00275 
00276         s = dev->subdevices+2;
00277         /* digital output subdevice */
00278         s->type = COMEDI_SUBD_DO;
00279         s->subdev_flags = SDF_WRITABLE;
00280         s->n_chan = thisboard->do_chans;
00281         s->maxdata = 1;
00282         s->range_table = &range_digital;
00283         s->insn_bits = adq12b_do_insn_bits;
00284 
00285 
00286         printk("attached\n");
00287 
00288         return 0;
00289 }
00290 
00291 
00292 /*
00293  * _detach is called to deconfigure a device.  It should deallocate
00294  * resources.
00295  * This function is also called when _attach() fails, so it should be
00296  * careful not to release resources that were not necessarily
00297  * allocated by _attach().  dev->private and dev->subdevices are
00298  * deallocated automatically by the core.
00299  */
00300 static int adq12b_detach(comedi_device *dev)
00301 {
00302         if (dev->iobase)
00303           release_region(dev->iobase, ADQ12B_SIZE);
00304 
00305         kfree(devpriv);
00306 
00307         printk("comedi%d: adq12b: removed\n",dev->minor);
00308 
00309         return 0;
00310 }
00311 
00312 /*
00313  * "instructions" read/write data in "one-shot" or "software-triggered"
00314  * mode.
00315  */
00316 
00317 static int adq12b_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
00318 {
00319         int n, i;
00320         int range, channel;
00321         unsigned char hi, lo, status;
00322 
00323         /* change channel and range only if it is different from the previous */
00324         range = CR_RANGE(insn->chanspec);
00325         channel = CR_CHAN(insn->chanspec);
00326         if (channel != devpriv->last_channel || range != devpriv->last_range) {
00327           outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
00328           comedi_udelay(50);   /* wait for the mux to settle */
00329         }
00330 
00331         /* trigger conversion */
00332         status = inb(dev->iobase + ADQ12B_ADLOW);
00333 
00334         /* convert n samples */
00335         for(n=0; n < insn->n; n++){
00336 
00337           /* wait for end of convertion */
00338           i = 0;
00339           do {
00340 //            comedi_udelay(1);
00341             status = inb(dev->iobase + ADQ12B_STINR);
00342             status = status & ADQ12B_EOC; 
00343           } while (status == 0 && ++i < TIMEOUT);
00344 //          } while (++i < 10);
00345 
00346           /* read data */
00347           hi = inb(dev->iobase + ADQ12B_ADHIG);
00348           lo = inb(dev->iobase + ADQ12B_ADLOW);
00349 
00350           //rt_printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", channel, range, status,  hi, lo);
00351           data[n] = (hi << 8) | lo;
00352 
00353         }
00354 
00355         /* return the number of samples read/written */
00356         return n;
00357 }
00358 
00359 
00360 static int adq12b_di_insn_bits(comedi_device *dev,comedi_subdevice *s,  comedi_insn *insn,lsampl_t *data)
00361 {
00362 
00363         /* only bits 0-4 have information about digital inputs */
00364         data[1] = (inb(dev->iobase+ADQ12B_STINR) & (0x1f));
00365 
00366         return 2;
00367 }
00368 
00369 
00370 static int adq12b_do_insn_bits(comedi_device *dev,comedi_subdevice *s,  comedi_insn *insn,lsampl_t *data)
00371 {
00372         int channel;
00373 
00374         for (channel = 0; channel < 8; channel++)
00375           if (((data[0]>>channel) & 0x01) != 0)
00376             outb((((data[1]>>channel)&0x01)<<3) | channel, dev->iobase + ADQ12B_OUTBR);
00377         
00378         /* store information to retrieve when asked for reading */
00379         if (data[0]) {
00380           devpriv->digital_state &= ~data[0];
00381           devpriv->digital_state |= (data[0]&data[1]);
00382         }
00383 
00384         data[1] = devpriv->digital_state;
00385 
00386         return 2;
00387 }
00388 
00389 
00390 /*
00391  * A convenient macro that defines init_module() and cleanup_module(),
00392  * as necessary.
00393  */
00394 COMEDI_INITCLEANUP(driver_adq12b);
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines