2 A little auto-calibration utility, for boards
5 copyright (C) 1999,2000,2001,2002 by David Schleef
6 copyright (C) 2003 by Frank Mori Hess
10 /***************************************************************************
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU Lesser General Public License as *
15 * the Free Software Foundation; either version 2.1 of the License, or *
16 * (at your option) any later version. *
18 ***************************************************************************/
36 char ni_id[] = "$Id$";
41 int (*cal)( calibration_setup_t *setup);
42 void (*setup_observables)( calibration_setup_t *setup );
47 static int ni_setup_board( calibration_setup_t *setup , const char *device_name );
48 static void ni_setup_observables( calibration_setup_t *setup );
49 static void ni_setup_observables_611x( calibration_setup_t *setup );
51 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup);
52 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup);
53 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup);
54 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup);
55 static int cal_ni_pci_6024e(calibration_setup_t *setup);
56 static int cal_ni_pci_6025e(calibration_setup_t *setup);
57 static int cal_ni_pci_6035e(calibration_setup_t *setup);
58 static int cal_ni_pci_6071e(calibration_setup_t *setup);
59 static int cal_ni_pxi_6071e(calibration_setup_t *setup);
60 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup);
61 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup);
62 static int cal_ni_pci_6023e(calibration_setup_t *setup);
63 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup);
64 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup);
65 static int cal_ni_pci_6052e(calibration_setup_t *setup);
66 static int cal_ni_pci_6032e(calibration_setup_t *setup);
67 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup);
68 static int cal_ni_pci_611x(calibration_setup_t *setup);
69 static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup);
70 static int cal_ni_daqcard_6062e(calibration_setup_t *setup);
71 static int cal_ni_daqcard_6024e(calibration_setup_t *setup);
73 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
75 static struct board_struct boards[]={
76 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
77 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
78 { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
79 { "at-mio-16e-1", STATUS_SOME, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
80 { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
81 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
82 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
83 { "pci-6071e", STATUS_SOME, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
84 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
85 { "at-mio-16e-10", STATUS_GUESS, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
86 { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
87 { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
88 { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
89 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
90 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
91 { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
92 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
93 { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
94 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
95 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
96 { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
97 { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
98 { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
99 { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
100 { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
101 { "pci-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1ae, 0x1af },
102 { "pci-6033e", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1ae, 0x1af },
104 { "at-mio-64e-3", cal_ni_16e_1 },
105 // { "at-mio-16xe-50", cal_ni_unknown },
106 // { "pxi-6030e", cal_ni_unknown },
107 // { "pxi-6040e", cal_ni_unknown },
108 { "pxi-6025e", cal_ni_6023e }, // guess
109 { "pci-6034e", cal_ni_6023e }, // guess
110 // { "pci-6711", cal_ni_unknown },
111 // { "pci-6713", cal_ni_unknown },
112 // { "pxi-6070e", cal_ni_unknown },
113 // { "pxi-6052e", cal_ni_unknown },
116 #define n_boards (sizeof(boards)/sizeof(boards[0]))
118 static const int ni_num_observables = 18;
120 ni_zero_offset_low = 0,
123 ni_unip_zero_offset_low,
124 ni_unip_zero_offset_high,
125 ni_unip_reference_low,
132 ni_ao0_unip_zero_offset,
133 ni_ao0_unip_reference,
134 ni_ao0_unip_linearity,
135 ni_ao1_unip_zero_offset,
136 ni_ao1_unip_reference,
137 ni_ao1_unip_linearity,
139 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
141 if( channel ) return ni_ao1_zero_offset;
142 else return ni_ao0_zero_offset;
144 static inline unsigned int ni_ao_reference( unsigned int channel )
146 if( channel ) return ni_ao1_reference;
147 else return ni_ao0_reference;
149 static inline unsigned int ni_ao_linearity( unsigned int channel )
151 if( channel ) return ni_ao1_linearity;
152 else return ni_ao0_linearity;
154 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
156 if( channel ) return ni_ao1_unip_zero_offset;
157 else return ni_ao0_unip_zero_offset;
159 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
161 if( channel ) return ni_ao1_unip_reference;
162 else return ni_ao0_unip_reference;
164 static inline unsigned int ni_ao_unip_linearity( unsigned int channel )
166 if( channel ) return ni_ao1_unip_linearity;
167 else return ni_ao0_unip_linearity;
170 static const int num_ao_observables_611x = 4;
171 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
172 unsigned int channel, unsigned int range ) {
173 assert( range == 0 );
176 static int ni_ao_reference_611x( const calibration_setup_t *setup,
177 unsigned int channel, unsigned int range ) {
178 assert( range == 0 );
179 return 2 * channel + 1;
181 static int ni_zero_offset_611x( const calibration_setup_t *setup,
182 unsigned int channel, unsigned int range ) {
183 return num_ao_observables_611x + 8 * range + 2 * channel;
185 static int ni_reference_611x( const calibration_setup_t *setup,
186 unsigned int channel, unsigned int range ) {
187 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
190 enum reference_sources {
195 REF_CALSRC_CALSRC = 4,
200 static inline unsigned int REF_DAC_GND( unsigned int channel )
202 if( channel ) return REF_DAC1_GND;
203 else return REF_DAC0_GND;
205 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
207 if( channel ) return REF_DAC1_CALSRC;
208 else return REF_DAC0_CALSRC;
211 static struct board_struct* ni_board( calibration_setup_t *setup )
213 return setup->private_data;
218 int adc_pregain_offset;
219 int adc_postgain_offset;
221 int adc_pregain_offset_fine;
222 int adc_postgain_offset_fine;
227 int dac_gain_fine[ 2 ];
228 int dac_linearity[ 2 ];
229 } ni_caldac_layout_t;
231 static int cal_ni_generic( calibration_setup_t *setup,
232 const ni_caldac_layout_t *layout );
234 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
238 layout->adc_pregain_offset = -1;
239 layout->adc_postgain_offset = -1;
240 layout->adc_gain = -1;
241 layout->adc_unip_offset = -1;
242 layout->adc_pregain_offset_fine = -1;
243 layout->adc_postgain_offset_fine = -1;
244 layout->adc_gain_fine = -1;
245 for( i = 0; i < 2; i++ )
247 layout->dac_offset[ i ] = -1;
248 layout->dac_gain[ i ] = -1;
249 layout->dac_gain_fine[ i ] = -1;
250 layout->dac_linearity[ i ] = -1;
254 int ni_setup( calibration_setup_t *setup , const char *device_name )
258 retval = ni_setup_board( setup, device_name );
259 if( retval < 0 ) return retval;
260 setup_caldacs( setup, setup->caldac_subdev );
265 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
269 for(i = 0; i < n_boards; i++ ){
270 if(!strcmp( device_name, boards[i].name )){
271 setup->status = boards[i].status;
272 setup->do_cal = boards[i].cal;
273 setup->private_data = &boards[ i ];
274 boards[i].setup_observables( setup );
278 if( i == n_boards ) return -1;
282 static void ni_setup_ao_observables( calibration_setup_t *setup )
285 comedi_insn tmpl, po_tmpl;
286 unsigned int channel;
287 int ai_bipolar_lowgain;
288 int ao_bipolar_lowgain;
289 int ao_unipolar_lowgain;
291 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
292 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
293 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
295 memset(&tmpl,0,sizeof(tmpl));
296 tmpl.insn = INSN_READ;
298 tmpl.subdev = setup->ad_subdev;
300 memset(&po_tmpl, 0, sizeof(po_tmpl));
301 po_tmpl.insn = INSN_WRITE;
303 po_tmpl.subdev = setup->da_subdev;
305 for( channel = 0; channel < 2; channel++ )
308 o = setup->observables + ni_ao_zero_offset( channel );
309 assert( o->name == NULL );
310 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
311 o->preobserve_insn = po_tmpl;
312 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
313 o->preobserve_insn.data = o->preobserve_data;
314 o->observe_insn = tmpl;
315 o->observe_insn.chanspec =
316 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
317 | CR_ALT_SOURCE | CR_ALT_FILTER;
318 o->reference_source = REF_DAC_GND( channel );
319 set_target( setup, ni_ao_zero_offset( channel ),0.0);
322 o = setup->observables + ni_ao_reference( channel );
323 assert( o->name == NULL );
324 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
325 o->preobserve_insn = po_tmpl;
326 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
327 o->preobserve_insn.data = o->preobserve_data;
328 o->observe_insn = tmpl;
329 o->observe_insn.chanspec =
330 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
331 | CR_ALT_SOURCE | CR_ALT_FILTER;
332 o->reference_source = REF_DAC_GND( channel );
333 set_target( setup, ni_ao_reference( channel ),5.0);
335 /* ao linearity, negative */
336 o = setup->observables + ni_ao_linearity( channel );
337 assert( o->name == NULL );
338 asprintf( &o->name, "ao %i, linearity (negative), low gain", channel );
339 o->preobserve_insn = po_tmpl;
340 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
341 o->preobserve_insn.data = o->preobserve_data;
342 o->observe_insn = tmpl;
343 o->observe_insn.chanspec =
344 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
345 | CR_ALT_SOURCE | CR_ALT_FILTER;
346 o->reference_source = REF_DAC_GND( channel );
347 set_target( setup, ni_ao_linearity( channel ),-5.0);
349 if( ao_unipolar_lowgain >= 0 )
351 /* ao unipolar zero offset */
352 o = setup->observables + ni_ao_unip_zero_offset( channel );
353 assert( o->name == NULL );
354 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
355 o->preobserve_insn = po_tmpl;
356 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
357 o->preobserve_insn.data = o->preobserve_data;
358 o->observe_insn = tmpl;
359 o->observe_insn.chanspec =
360 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
361 | CR_ALT_SOURCE | CR_ALT_FILTER;
362 o->reference_source = REF_DAC_GND( channel );
363 set_target( setup, ni_ao_zero_offset( channel ),0.0);
365 /* ao unipolar gain */
366 o = setup->observables + ni_ao_unip_reference( channel );
367 assert( o->name == NULL );
368 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
369 o->preobserve_insn = po_tmpl;
370 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
371 o->preobserve_insn.data = o->preobserve_data;
372 o->observe_insn = tmpl;
373 o->observe_insn.chanspec =
374 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
375 | CR_ALT_SOURCE | CR_ALT_FILTER;
376 o->reference_source = REF_DAC_GND( channel );
377 set_target( setup, ni_ao_reference( channel ),8.0);
379 /* ao unipolar linearity, negative */
380 o = setup->observables + ni_ao_unip_linearity( channel );
381 assert( o->name == NULL );
382 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
383 o->preobserve_insn = po_tmpl;
384 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
385 o->preobserve_insn.data = o->preobserve_data;
386 o->observe_insn = tmpl;
387 o->observe_insn.chanspec =
388 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
389 | CR_ALT_SOURCE | CR_ALT_FILTER;
390 o->reference_source = REF_DAC_GND( channel );
391 set_target( setup, ni_ao_linearity( channel ),4.0);
396 static void ni_setup_observables( calibration_setup_t *setup )
400 int bipolar_highgain;
401 int unipolar_lowgain;
402 int unipolar_highgain;
403 double voltage_reference;
406 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
407 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
408 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
409 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
411 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
412 ni_board( setup )->ref_eeprom_msb >= 0 )
414 voltage_reference = ni_get_reference( setup,
415 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
418 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
419 "correction. This might be fixable if you send us an eeprom dump\n"
420 "(see the demo/eeprom_dump program).\n");
421 voltage_reference = 5.0;
424 memset(&tmpl,0,sizeof(tmpl));
425 tmpl.insn = INSN_READ;
427 tmpl.subdev = setup->ad_subdev;
429 setup->n_observables = ni_num_observables;
431 /* 0 offset, low gain */
432 o = setup->observables + ni_zero_offset_low;
433 o->name = "ai, bipolar zero offset, low gain";
434 o->observe_insn = tmpl;
435 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
436 | CR_ALT_SOURCE | CR_ALT_FILTER;
437 o->reference_source = REF_GND_GND;
440 /* 0 offset, high gain */
441 o = setup->observables + ni_zero_offset_high;
442 o->name = "ai, bipolar zero offset, high gain";
443 o->observe_insn = tmpl;
444 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
445 | CR_ALT_SOURCE | CR_ALT_FILTER;
446 o->reference_source = REF_GND_GND;
449 /* voltage reference */
450 o = setup->observables + ni_reference_low;
451 o->name = "ai, bipolar voltage reference, low gain";
452 o->observe_insn = tmpl;
453 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
454 | CR_ALT_SOURCE | CR_ALT_FILTER;
455 o->reference_source = REF_CALSRC_GND;
456 o->target = voltage_reference;
458 if(unipolar_lowgain>=0){
459 o = setup->observables + ni_unip_zero_offset_low;
460 o->name = "ai, unipolar zero offset, low gain";
461 o->observe_insn = tmpl;
462 o->observe_insn.chanspec =
463 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
464 | CR_ALT_SOURCE | CR_ALT_FILTER;
465 o->reference_source = REF_GND_GND;
466 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
468 o = setup->observables + ni_unip_reference_low;
469 o->name = "ai, unipolar voltage reference, low gain";
470 o->observe_insn = tmpl;
471 o->observe_insn.chanspec =
472 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
473 | CR_ALT_SOURCE | CR_ALT_FILTER;
474 o->reference_source = REF_CALSRC_GND;
475 o->target = voltage_reference;
478 if(unipolar_highgain >= 0)
480 o = setup->observables + ni_unip_zero_offset_high;
481 o->name = "ai, unipolar zero offset, high gain";
482 o->observe_insn = tmpl;
483 o->observe_insn.chanspec =
484 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
485 | CR_ALT_SOURCE | CR_ALT_FILTER;
486 o->reference_source = REF_GND_GND;
487 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
490 if(setup->da_subdev >= 0)
491 ni_setup_ao_observables( setup );
494 /* for +-50V and +-20V ranges, the reference source goes 0V
495 * to 50V instead of 0V to 5V */
496 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
500 bits = 200.0 * ( *voltage / reference );
501 if( bits > 200 ) bits = 200;
502 if( bits < 0 ) bits = 0;
504 *voltage = reference * ( bits / 200.0 );
508 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
510 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
513 static void reference_target_611x( calibration_setup_t *setup,
514 observable *o, double master_reference, unsigned int range )
516 int cal_gain_reg_bits;
519 comedi_range *range_ptr;
521 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
522 assert( range_ptr != NULL );
523 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
524 else reference = master_reference;
525 target = range_ptr->max * 0.8;
527 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
529 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
533 static void ni_setup_observables_611x( calibration_setup_t *setup )
538 double master_reference;
540 int num_ai_channels, num_ai_ranges;
541 static const int num_ao_channels = 2;
543 setup->sv_settling_time_ns = 10000000;
544 setup->sv_order = 14;
546 master_reference = ni_get_reference( setup,
547 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
549 memset(&tmpl,0,sizeof(tmpl));
550 tmpl.insn = INSN_READ;
552 tmpl.subdev = setup->ad_subdev;
554 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
555 assert( num_ai_channels >= 0 );
556 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
557 assert( num_ai_ranges >= 0 );
559 for( channel = 0; channel < num_ai_channels; channel++ )
561 for( range = 0; range < num_ai_ranges; range++ )
564 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
565 assert( o->name == NULL );
566 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
568 o->observe_insn = tmpl;
569 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
570 | CR_ALT_SOURCE | CR_ALT_FILTER;
571 o->reference_source = REF_GND_GND;
574 /* voltage reference */
575 o = setup->observables + ni_reference_611x( setup, channel, range );
576 assert( o->name == NULL );
577 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
579 o->observe_insn = tmpl;
580 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
581 | CR_ALT_SOURCE | CR_ALT_FILTER;
582 reference_target_611x( setup, o, master_reference, range );
586 memset(&po_tmpl,0,sizeof(po_tmpl));
587 po_tmpl.insn = INSN_WRITE;
589 po_tmpl.subdev = setup->da_subdev;
591 for( channel = 0; channel < num_ao_channels; channel ++ )
593 static const int ai_range_for_ao = 2;
596 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
597 assert( o->name == NULL );
598 asprintf( &o->name, "ao ch %i, zero offset", channel );
599 o->preobserve_insn = po_tmpl;
600 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
601 o->preobserve_insn.data = o->preobserve_data;
602 o->observe_insn = tmpl;
603 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
604 | CR_ALT_SOURCE | CR_ALT_FILTER;
605 o->reference_source = REF_DAC_GND( channel );
606 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
609 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
610 assert( o->name == NULL );
611 asprintf( &o->name, "ao ch %i, reference voltage", channel );
612 o->preobserve_insn = po_tmpl;
613 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
614 o->preobserve_insn.data = o->preobserve_data;
615 o->observe_insn = tmpl;
616 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
617 | CR_ALT_SOURCE | CR_ALT_FILTER;
618 o->reference_source = REF_DAC_GND( channel );
619 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
622 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
625 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
627 ni_caldac_layout_t layout;
629 init_ni_caldac_layout( &layout );
630 layout.adc_pregain_offset = 0;
631 layout.adc_postgain_offset = 1;
633 layout.adc_unip_offset = 2;
634 layout.dac_offset[ 0 ] = 5;
635 layout.dac_gain[ 0 ] = 6;
636 layout.dac_offset[ 1 ] = 8;
637 layout.dac_gain[ 1 ] = 9;
639 return cal_ni_generic( setup, &layout );
642 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
644 ni_caldac_layout_t layout;
646 init_ni_caldac_layout( &layout );
647 layout.adc_pregain_offset = 8;
648 layout.adc_postgain_offset = 2;
650 layout.adc_gain_fine = 1;
652 return cal_ni_generic( setup, &layout );
655 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
657 ni_caldac_layout_t layout;
659 init_ni_caldac_layout( &layout );
660 layout.adc_pregain_offset = 8;
661 layout.adc_postgain_offset = 2;
663 layout.adc_gain_fine = 1;
664 layout.dac_offset[ 0 ] = 6;
665 layout.dac_gain[ 0 ] = 4;
666 layout.dac_offset[ 1 ] = 7;
667 layout.dac_gain[ 1 ] = 5;
669 return cal_ni_generic( setup, &layout );
672 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
674 ni_caldac_layout_t layout;
676 init_ni_caldac_layout( &layout );
677 layout.adc_pregain_offset = 8;
678 layout.adc_postgain_offset = 2;
679 layout.adc_postgain_offset_fine = 3;
681 layout.adc_gain_fine = 1;
682 layout.dac_offset[ 0 ] = 6;
683 layout.dac_gain[ 0 ] = 4;
684 layout.dac_offset[ 1 ] = 7;
685 layout.dac_gain[ 1 ] = 5;
687 return cal_ni_generic( setup, &layout );
690 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
692 return cal_ni_at_mio_16e_2( setup );
695 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
697 ni_caldac_layout_t layout;
699 init_ni_caldac_layout( &layout );
700 layout.adc_pregain_offset = 0;
701 layout.adc_postgain_offset = 1;
702 layout.adc_unip_offset = 2;
704 layout.dac_offset[ 0 ] = 5;
705 layout.dac_gain[ 0 ] = 6;
706 layout.dac_linearity[ 0 ] = 4;
707 layout.dac_offset[ 1 ] = 8;
708 layout.dac_gain[ 1 ] = 9;
709 layout.dac_linearity[ 1 ] = 7;
711 return cal_ni_generic( setup, &layout );
714 static int cal_ni_pci_6032e(calibration_setup_t *setup)
716 ni_caldac_layout_t layout;
718 init_ni_caldac_layout( &layout );
719 layout.adc_pregain_offset = 8;
720 layout.adc_postgain_offset = 2;
721 layout.adc_postgain_offset_fine = 3;
723 layout.adc_gain_fine = 1;
725 return cal_ni_generic( setup, &layout );
728 static int cal_ni_pci_6035e(calibration_setup_t *setup)
730 /* this is for the ad8804_debug caldac */
731 ni_caldac_layout_t layout;
733 init_ni_caldac_layout( &layout );
734 layout.adc_pregain_offset = 0;
735 layout.adc_pregain_offset_fine = 8;
736 layout.adc_postgain_offset = 4;
738 layout.dac_offset[ 0 ] = 6;
739 layout.dac_gain[ 0 ] = 11;
740 layout.dac_linearity[ 0 ] = 10;
741 layout.dac_offset[ 1 ] = 9;
742 layout.dac_gain[ 1 ] = 5;
743 layout.dac_linearity[ 1 ] = 1;
745 return cal_ni_generic( setup, &layout );
748 static int cal_ni_pci_6071e(calibration_setup_t *setup)
750 ni_caldac_layout_t layout;
752 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
754 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
755 "for this calibration to work properly\n" );
758 init_ni_caldac_layout( &layout );
759 layout.adc_pregain_offset = 0;
760 layout.adc_pregain_offset_fine = 8;
761 layout.adc_postgain_offset = 4;
763 layout.dac_offset[ 0 ] = 6;
764 layout.dac_gain[ 0 ] = 11;
765 layout.dac_linearity[ 0 ] = 10;
766 layout.dac_offset[ 1 ] = 9;
767 layout.dac_gain[ 1 ] = 5;
768 layout.dac_linearity[ 1 ] = 1;
769 return cal_ni_generic( setup, &layout );
772 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
774 ni_caldac_layout_t layout;
776 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
778 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
779 "for this calibration to work properly\n" );
782 init_ni_caldac_layout( &layout );
783 layout.adc_pregain_offset = 0;
784 layout.adc_pregain_offset_fine = 8;
785 layout.adc_postgain_offset = 4;
787 layout.dac_offset[ 0 ] = 6;
788 layout.dac_gain[ 0 ] = 11;
789 layout.dac_linearity[ 0 ] = 10;
790 layout.dac_offset[ 1 ] = 9;
791 layout.dac_gain[ 1 ] = 5;
792 layout.dac_linearity[ 1 ] = 1;
793 return cal_ni_generic( setup, &layout );
796 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
799 ni_caldac_layout_t layout;
801 init_ni_caldac_layout( &layout );
802 layout.adc_pregain_offset = 10;
803 layout.adc_pregain_offset_fine = 0;
804 layout.adc_postgain_offset = 1;
806 layout.adc_unip_offset = 2;
807 layout.dac_offset[ 0 ] = 5; /* guess */
808 layout.dac_gain[ 0 ] = 6; /* guess */
809 layout.dac_offset[ 1 ] = 8; /* guess */
810 layout.dac_gain[ 1 ] = 9; /* guess */
812 return cal_ni_generic( setup, &layout );
815 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
817 ni_caldac_layout_t layout;
819 init_ni_caldac_layout( &layout );
820 layout.adc_pregain_offset = 8;
821 layout.adc_postgain_offset = 2;
823 layout.adc_gain_fine = 1;
824 layout.adc_unip_offset = 7;
825 layout.dac_offset[ 0 ] = 6;
826 layout.dac_gain[ 0 ] = 4;
827 layout.dac_offset[ 1 ] = 7;
828 layout.dac_gain[ 1 ] = 5;
830 return cal_ni_generic( setup, &layout );
833 static int cal_ni_pci_6023e(calibration_setup_t *setup)
835 /* for comedi-0.7.65 */
836 ni_caldac_layout_t layout;
838 init_ni_caldac_layout( &layout );
839 layout.adc_pregain_offset = 8; /* possibly wrong */
840 layout.adc_pregain_offset_fine = 0;
841 layout.adc_postgain_offset = 4;
844 return cal_ni_generic( setup, &layout );
847 static int cal_ni_pci_6024e(calibration_setup_t *setup)
849 ni_caldac_layout_t layout;
851 init_ni_caldac_layout( &layout );
852 layout.adc_pregain_offset = 8;
853 layout.adc_postgain_offset = 4;
854 layout.adc_pregain_offset_fine = 0;
856 layout.dac_offset[ 0 ] = 6;
857 layout.dac_gain[ 0 ] = 11;
858 layout.dac_linearity[ 0 ] = 10;
859 layout.dac_offset[ 1 ] = 9;
860 layout.dac_gain[ 1 ] = 5;
861 layout.dac_linearity[ 1 ] = 1;
863 return cal_ni_generic( setup, &layout );
866 static int cal_ni_pci_6025e(calibration_setup_t *setup)
868 ni_caldac_layout_t layout;
870 init_ni_caldac_layout( &layout );
871 layout.adc_pregain_offset = 8;
872 layout.adc_postgain_offset = 4;
873 layout.adc_pregain_offset_fine = 0;
875 layout.dac_offset[ 0 ] = 6;
876 layout.dac_gain[ 0 ] = 11;
877 layout.dac_linearity[ 0 ] = 10;
878 layout.dac_offset[ 1 ] = 9;
879 layout.dac_gain[ 1 ] = 5;
880 layout.dac_linearity[ 1 ] = 1;
882 return cal_ni_generic( setup, &layout );
885 static int cal_ni_pci_6052e(calibration_setup_t *setup)
888 * This board has noisy caldacs
890 * The NI documentation says (true mb88341 addressing):
891 * 0, 8 AI pregain (coarse, fine)
894 * 14, 7 AI unipolar offset
900 * 10, 6 AO1 reference
903 * For us, these map to (ad8804 channels)
905 * 0, 1 AI pregain (coarse, fine)
908 * 7 AI unipolar offset
917 * or, with mb88341 channels
927 ni_caldac_layout_t layout;
929 init_ni_caldac_layout( &layout );
930 layout.adc_pregain_offset = 0;
931 layout.adc_postgain_offset = 2;
933 layout.adc_unip_offset = 6;
934 layout.adc_pregain_offset_fine = 1;
935 layout.adc_postgain_offset_fine = 3;
936 layout.adc_gain_fine = 5;
938 /* this seems broken, i think we need to change
939 * second caldac in driver to ad8804_debug */
940 layout.dac_offset[ 0 ] = 12 + 11;
941 layout.dac_gain[ 0 ] = 12 + 7;
942 layout.dac_gain_fine[ 0 ] = 12 + 3;
943 layout.dac_offset[ 1 ] = 12 + 1;
944 layout.dac_gain[ 1 ] = 12 + 9;
945 layout.dac_gain_fine[ 1 ] = 12 + 5;
947 /* this should work if the first two caldacs were ad8804_debug */
948 layout.dac_offset[ 0 ] = 16 + 3;
949 layout.dac_gain[ 0 ] = 16 + 1;
950 layout.dac_gain_fine[ 0 ] = 16 + 2;
951 layout.dac_linearity[ 0 ] = 16 + 0;
952 layout.dac_offset[ 1 ] = 16 + 7;
953 layout.dac_gain[ 1 ] = 16 + 5;
954 layout.dac_gain_fine[ 1 ] = 16 + 6;
955 layout.dac_linearity[ 1 ] = 16 + 4;
957 return cal_ni_generic( setup, &layout );
960 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
962 ni_caldac_layout_t layout;
964 init_ni_caldac_layout( &layout );
965 layout.adc_pregain_offset = 0;
966 layout.adc_postgain_offset = 1;
968 layout.adc_unip_offset = 2;
970 return cal_ni_generic( setup, &layout );
973 static int adc_offset_611x( unsigned int channel )
975 return 2 * channel + 2;
977 static int adc_gain_611x( unsigned int channel )
979 return 2 * channel + 1;
981 static int dac_offset_611x( unsigned int channel )
983 return 12 + 2 + 2 * channel;
985 static int dac_gain_611x( unsigned int channel )
987 return 12 + 1 + 2 * channel;
989 static int cal_ni_pci_611x( calibration_setup_t *setup )
991 generic_layout_t layout;
993 init_generic_layout( &layout );
994 layout.adc_offset = adc_offset_611x;
995 layout.adc_gain = adc_gain_611x;
996 layout.dac_offset = dac_offset_611x;
997 layout.dac_gain = dac_gain_611x;
998 layout.adc_high_observable = ni_reference_611x;
999 layout.adc_ground_observable = ni_zero_offset_611x;
1000 layout.dac_high_observable = ni_ao_reference_611x;
1001 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1003 return generic_cal_by_channel_and_range( setup, &layout );
1006 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1008 ni_caldac_layout_t layout;
1010 init_ni_caldac_layout( &layout );
1011 layout.adc_pregain_offset = 8;
1012 layout.adc_postgain_offset = 4;
1013 layout.adc_gain = 2;
1014 layout.adc_unip_offset = 7;
1015 layout.dac_offset[ 0 ] = 6;
1016 layout.dac_gain[ 0 ] = 11;
1017 layout.dac_linearity[ 0 ] = 10;
1018 layout.dac_offset[ 1 ] = 9;
1019 layout.dac_gain[ 1 ] = 5;
1020 layout.dac_linearity[ 1 ] = 1;
1022 return cal_ni_generic( setup, &layout );
1025 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1027 ni_caldac_layout_t layout;
1029 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1031 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1032 "for this calibration to work properly\n" );
1034 init_ni_caldac_layout( &layout );
1035 layout.adc_pregain_offset = 8;
1036 layout.adc_postgain_offset = 4;
1037 layout.adc_gain = 2;
1038 layout.adc_unip_offset = 7;
1039 layout.dac_offset[ 0 ] = 6;
1040 layout.dac_gain[ 0 ] = 11;
1041 layout.dac_linearity[ 0 ] = 10;
1042 layout.dac_offset[ 1 ] = 9;
1043 layout.dac_gain[ 1 ] = 5;
1044 layout.dac_linearity[ 1 ] = 1;
1046 return cal_ni_generic( setup, &layout );
1049 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1051 ni_caldac_layout_t layout;
1053 init_ni_caldac_layout( &layout );
1055 layout.adc_pregain_offset = 0;
1056 layout.adc_postgain_offset = 4;
1057 layout.adc_gain = 2;
1058 //layout.adc_unip_offset = 7;
1059 layout.dac_offset[ 0 ] = 6;
1060 layout.dac_gain[ 0 ] = 3;
1061 //layout.dac_linearity[ 0 ] = 10;
1062 layout.dac_offset[ 1 ] = 1;
1063 layout.dac_gain[ 1 ] = 5;
1064 //layout.dac_linearity[ 1 ] = 1;
1066 return cal_ni_generic( setup, &layout );
1069 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1070 const ni_caldac_layout_t *layout )
1074 if( setup->old_calibration == NULL )
1076 reset_caldac( setup, layout->adc_pregain_offset );
1077 reset_caldac( setup, layout->adc_postgain_offset );
1078 reset_caldac( setup, layout->adc_gain );
1079 reset_caldac( setup, layout->adc_pregain_offset_fine );
1080 reset_caldac( setup, layout->adc_postgain_offset_fine );
1081 reset_caldac( setup, layout->adc_gain_fine );
1082 reset_caldac( setup, layout->adc_unip_offset );
1085 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1086 0, 0, AREF_GROUND, setup->old_calibration );
1089 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1090 reset_caldac( setup, layout->adc_pregain_offset );
1091 reset_caldac( setup, layout->adc_postgain_offset );
1092 reset_caldac( setup, layout->adc_gain );
1093 reset_caldac( setup, layout->adc_pregain_offset_fine );
1094 reset_caldac( setup, layout->adc_postgain_offset_fine );
1095 reset_caldac( setup, layout->adc_gain_fine );
1096 reset_caldac( setup, layout->adc_unip_offset );
1101 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1102 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1106 if( setup->da_subdev < 0 ) return;
1108 if( setup->old_calibration == NULL )
1110 reset_caldac( setup, layout->dac_offset[ channel ] );
1111 reset_caldac( setup, layout->dac_gain[ channel ] );
1112 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1113 reset_caldac( setup, layout->dac_linearity[ channel ] );
1116 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1117 channel, range, AREF_GROUND, setup->old_calibration );
1120 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1121 reset_caldac( setup, layout->dac_offset[ channel ] );
1122 reset_caldac( setup, layout->dac_gain[ channel ] );
1123 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1124 reset_caldac( setup, layout->dac_linearity[ channel ] );
1129 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1131 comedi_calibration_setting_t *current_cal;
1134 prep_adc_caldacs_generic( setup, layout );
1136 current_cal = sc_alloc_calibration_setting( setup );
1137 current_cal->subdevice = setup->ad_subdev;
1138 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1139 ni_reference_low, layout->adc_gain );
1140 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1141 ni_zero_offset_high, layout->adc_postgain_offset );
1142 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1143 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1144 ni_reference_low, layout->adc_gain_fine );
1145 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1146 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1147 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1148 layout->adc_pregain_offset_fine );
1149 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high, layout->adc_unip_offset );
1150 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1151 sc_push_range( current_cal, SC_ALL_RANGES );
1152 sc_push_aref( current_cal, SC_ALL_AREFS );
1154 if( setup->da_subdev >= 0 && setup->do_output )
1156 unsigned int channel, range;
1157 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1158 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1161 for( channel = 0; channel < 2; channel++ )
1163 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1164 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1166 current_cal = sc_alloc_calibration_setting( setup );
1167 current_cal->subdevice = setup->da_subdev;
1168 generic_do_linearity( setup, current_cal, ni_ao_linearity( channel ),
1169 ni_ao_zero_offset( channel ), ni_ao_reference( channel ),
1170 layout->dac_linearity[ channel ] );
1171 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1172 layout->dac_offset[ channel ] );
1173 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1174 layout->dac_gain[ channel ] );
1175 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1176 layout->dac_gain_fine[ channel ] );
1177 sc_push_channel( current_cal, channel );
1178 for( range = 0; range < num_ao_ranges; range++ )
1180 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1181 sc_push_range( current_cal, range );
1183 sc_push_aref( current_cal, SC_ALL_AREFS );
1185 if( ao_unipolar_lowgain >= 0 )
1187 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1189 current_cal = sc_alloc_calibration_setting( setup );
1190 current_cal->subdevice = setup->da_subdev;
1191 generic_do_linearity( setup, current_cal, ni_ao_unip_zero_offset( channel ),
1192 ni_ao_unip_linearity( channel ), ni_ao_unip_reference( channel ),
1193 layout->dac_linearity[ channel ] );
1194 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1195 layout->dac_offset[ channel ] );
1196 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1197 layout->dac_gain[ channel ] );
1198 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1199 layout->dac_gain_fine[ channel ] );
1200 sc_push_channel( current_cal, channel );
1201 for( range = 0; range < num_ao_ranges; range++ )
1203 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1204 sc_push_range( current_cal, range );
1206 sc_push_aref( current_cal, SC_ALL_AREFS );
1211 retval = write_calibration_file( setup );
1216 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1222 lsb=read_eeprom( setup, lsb_loc );
1223 msb=read_eeprom( setup, msb_loc );
1224 assert( lsb >=0 && msb >= 0 );
1225 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1227 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1228 ref=5.000+1.0e-6*uv;
1229 DPRINT(0, "resulting reference voltage: %g\n", ref );
1230 if( fabs( ref - 5.0 ) > 0.005 )
1231 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1232 "from 5V. Possible bad eeprom address?\n" );