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 );
50 static void ni67xx_setup_observables( calibration_setup_t *setup );
52 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup);
53 static int cal_ni_at_mio_64e_3(calibration_setup_t *setup);
54 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup);
55 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup);
56 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup);
57 static int cal_ni_pci_6014(calibration_setup_t *setup);
58 static int cal_ni_pci_6024e(calibration_setup_t *setup);
59 static int cal_ni_pci_6025e(calibration_setup_t *setup);
60 static int cal_ni_pci_6032e(calibration_setup_t *setup);
61 static int cal_ni_pci_6034e(calibration_setup_t *setup);
62 static int cal_ni_pci_6035e(calibration_setup_t *setup);
63 static int cal_ni_pci_6036e(calibration_setup_t *setup);
64 static int cal_ni_pci_6071e(calibration_setup_t *setup);
65 static int cal_ni_pxi_6071e(calibration_setup_t *setup);
66 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup);
67 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup);
68 static int cal_ni_pci_6023e(calibration_setup_t *setup);
69 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup);
70 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup);
71 static int cal_ni_pci_6052e(calibration_setup_t *setup);
72 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup);
73 static int cal_ni_pci_611x(calibration_setup_t *setup);
74 static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup);
75 static int cal_ni_daqcard_6062e(calibration_setup_t *setup);
76 static int cal_ni_daqcard_6024e(calibration_setup_t *setup);
77 static int cal_ni_daqcard_6036e(calibration_setup_t *setup);
78 static int cal_ni_pci_6711(calibration_setup_t *setup);
80 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
82 static struct board_struct boards[]={
83 { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
84 { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
85 { "at-mio-16e-1", STATUS_DONE, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
86 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
87 { "at-mio-16e-10", STATUS_DONE, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
88 { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
89 { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
90 { "at-mio-64e-3", STATUS_SOME, cal_ni_at_mio_64e_3, ni_setup_observables, 0x1a9, 0x1aa},
91 { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
92 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
93 { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
94 { "DAQCard-6036E", STATUS_DONE, cal_ni_daqcard_6036e, ni_setup_observables, 0x1ab, 0x1ac },
95 { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
96 { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
97 { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
98 { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
99 { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
100 { "pci-6014", STATUS_DONE, cal_ni_pci_6014, ni_setup_observables, 0x1ab, 0x1ac },
101 { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
102 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
103 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
104 { "pci-6031e", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
105 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
106 { "pci-6033e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1b7, 0x1b8 },
107 { "pci-6034e", STATUS_DONE, cal_ni_pci_6034e, ni_setup_observables, 0x1bb, 0x1bc },
108 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
109 { "pci-6036e", STATUS_DONE, cal_ni_pci_6036e, ni_setup_observables, 0x1ab, 0x1ac },
110 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
111 { "pci-6071e", STATUS_DONE, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
112 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
113 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
114 { "pxi-6025e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
115 { "pxi-6030e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
116 { "pxi-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
117 { "pxi-6040e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
118 { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
119 { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
120 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
121 { "pci-6711", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
122 { "pci-6713", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
123 { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
124 { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
125 { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
126 { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
127 { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
128 { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
130 { "at-mio-64e-3", cal_ni_16e_1 },
133 #define n_boards (sizeof(boards)/sizeof(boards[0]))
135 static const int ni_num_observables = 20;
137 ni_zero_offset_low = 0,
140 ni_unip_zero_offset_low,
141 ni_unip_zero_offset_high,
142 ni_unip_reference_low,
149 ni_ao0_unip_zero_offset,
150 ni_ao0_unip_reference,
151 ni_ao0_unip_low_linearity,
152 ni_ao0_unip_mid_linearity,
153 ni_ao1_unip_zero_offset,
154 ni_ao1_unip_reference,
155 ni_ao1_unip_low_linearity,
156 ni_ao1_unip_mid_linearity,
158 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
160 if( channel ) return ni_ao1_zero_offset;
161 else return ni_ao0_zero_offset;
163 static inline unsigned int ni_ao_reference( unsigned int channel )
165 if( channel ) return ni_ao1_reference;
166 else return ni_ao0_reference;
168 static inline unsigned int ni_ao_mid_linearity( unsigned int channel )
170 if( channel ) return ni_ao1_linearity;
171 else return ni_ao0_linearity;
173 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
175 if( channel ) return ni_ao1_unip_zero_offset;
176 else return ni_ao0_unip_zero_offset;
178 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
180 if( channel ) return ni_ao1_unip_reference;
181 else return ni_ao0_unip_reference;
183 static inline unsigned int ni_ao_unip_low_linearity( unsigned int channel )
185 if( channel ) return ni_ao1_unip_low_linearity;
186 else return ni_ao0_unip_low_linearity;
188 static inline unsigned int ni_ao_unip_mid_linearity( unsigned int channel )
190 if( channel ) return ni_ao1_unip_mid_linearity;
191 else return ni_ao0_unip_mid_linearity;
194 static const int num_ao_observables_611x = 4;
195 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
196 unsigned int channel, unsigned int range ) {
197 assert( range == 0 );
200 static int ni_ao_reference_611x( const calibration_setup_t *setup,
201 unsigned int channel, unsigned int range ) {
202 assert( range == 0 );
203 return 2 * channel + 1;
205 static int ni_zero_offset_611x( const calibration_setup_t *setup,
206 unsigned int channel, unsigned int range ) {
207 return num_ao_observables_611x + 8 * range + 2 * channel;
209 static int ni_reference_611x( const calibration_setup_t *setup,
210 unsigned int channel, unsigned int range ) {
211 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
214 enum reference_sources {
219 REF_CALSRC_CALSRC = 4,
224 static inline unsigned int REF_DAC_GND( unsigned int channel )
226 if( channel ) return REF_DAC1_GND;
227 else return REF_DAC0_GND;
229 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
231 if( channel ) return REF_DAC1_CALSRC;
232 else return REF_DAC0_CALSRC;
235 static struct board_struct* ni_board( calibration_setup_t *setup )
237 return setup->private_data;
242 int adc_pregain_offset;
243 int adc_postgain_offset;
245 int adc_pregain_offset_fine;
246 int adc_postgain_offset_fine;
249 int adc_unip_offset_fine;
251 int dac_offset_fine[ 2 ];
253 int dac_gain_fine[ 2 ];
254 int dac_linearity[ 2 ];
255 } ni_caldac_layout_t;
257 static int cal_ni_generic( calibration_setup_t *setup,
258 const ni_caldac_layout_t *layout );
260 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
264 layout->adc_pregain_offset = -1;
265 layout->adc_postgain_offset = -1;
266 layout->adc_gain = -1;
267 layout->adc_unip_offset = -1;
268 layout->adc_unip_offset_fine = -1;
269 layout->adc_pregain_offset_fine = -1;
270 layout->adc_postgain_offset_fine = -1;
271 layout->adc_gain_fine = -1;
272 for( i = 0; i < 2; i++ )
274 layout->dac_offset[ i ] = -1;
275 layout->dac_offset_fine[ i ] = -1;
276 layout->dac_gain[ i ] = -1;
277 layout->dac_gain_fine[ i ] = -1;
278 layout->dac_linearity[ i ] = -1;
282 int ni_setup( calibration_setup_t *setup , const char *device_name )
286 retval = ni_setup_board( setup, device_name );
287 if( retval < 0 ) return retval;
288 setup_caldacs( setup, setup->caldac_subdev );
293 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
297 for(i = 0; i < n_boards; i++ ){
298 if(!strcmp( device_name, boards[i].name )){
299 setup->status = boards[i].status;
300 setup->do_cal = boards[i].cal;
301 setup->private_data = &boards[ i ];
302 boards[i].setup_observables( setup );
306 if( i == n_boards ) return -1;
310 static void ni_setup_ao_observables( calibration_setup_t *setup )
313 comedi_insn tmpl, po_tmpl;
314 unsigned int channel;
315 int ai_bipolar_lowgain;
316 int ao_bipolar_lowgain;
317 int ao_unipolar_lowgain;
319 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
320 assert(ai_bipolar_lowgain >= 0);
321 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
322 assert(ao_bipolar_lowgain >= 0);
323 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
325 memset(&tmpl,0,sizeof(tmpl));
326 tmpl.insn = INSN_READ;
328 tmpl.subdev = setup->ad_subdev;
330 memset(&po_tmpl, 0, sizeof(po_tmpl));
331 po_tmpl.insn = INSN_WRITE;
333 po_tmpl.subdev = setup->da_subdev;
335 for( channel = 0; channel < 2; channel++ )
338 o = setup->observables + ni_ao_zero_offset( channel );
339 assert( o->name == NULL );
340 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
341 o->preobserve_insn = po_tmpl;
342 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
343 o->preobserve_insn.data = o->preobserve_data;
344 o->observe_insn = tmpl;
345 o->observe_insn.chanspec =
346 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
347 | CR_ALT_SOURCE | CR_ALT_FILTER;
348 o->reference_source = REF_DAC_GND( channel );
349 set_target( setup, ni_ao_zero_offset( channel ),0.0);
352 o = setup->observables + ni_ao_reference( channel );
353 assert( o->name == NULL );
354 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
355 o->preobserve_insn = po_tmpl;
356 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_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_reference( channel ),8.0);
365 /* ao linearity, mid */
366 o = setup->observables + ni_ao_mid_linearity( channel );
367 assert( o->name == NULL );
368 asprintf( &o->name, "ao %i, linearity (mid), low gain", channel );
369 o->preobserve_insn = po_tmpl;
370 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_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_mid_linearity( channel ),4.0);
379 if( ao_unipolar_lowgain >= 0 )
381 /* ao unipolar zero offset */
382 o = setup->observables + ni_ao_unip_zero_offset( channel );
383 assert( o->name == NULL );
384 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
385 o->preobserve_insn = po_tmpl;
386 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
387 o->preobserve_insn.data = o->preobserve_data;
388 o->observe_insn = tmpl;
389 o->observe_insn.chanspec =
390 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
391 | CR_ALT_SOURCE | CR_ALT_FILTER;
392 o->reference_source = REF_DAC_GND( channel );
393 set_target( setup, ni_ao_unip_zero_offset( channel ),0.0);
395 /* ao unipolar gain */
396 o = setup->observables + ni_ao_unip_reference( channel );
397 assert( o->name == NULL );
398 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
399 o->preobserve_insn = po_tmpl;
400 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
401 o->preobserve_insn.data = o->preobserve_data;
402 o->observe_insn = tmpl;
403 o->observe_insn.chanspec =
404 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
405 | CR_ALT_SOURCE | CR_ALT_FILTER;
406 o->reference_source = REF_DAC_GND( channel );
407 set_target( setup, ni_ao_unip_reference( channel ), 9.0);
409 /* ao unipolar linearity, mid */
410 o = setup->observables + ni_ao_unip_mid_linearity( channel );
411 assert( o->name == NULL );
412 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
413 o->preobserve_insn = po_tmpl;
414 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
415 o->preobserve_insn.data = o->preobserve_data;
416 o->observe_insn = tmpl;
417 o->observe_insn.chanspec =
418 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
419 | CR_ALT_SOURCE | CR_ALT_FILTER;
420 o->reference_source = REF_DAC_GND( channel );
421 set_target( setup, ni_ao_unip_mid_linearity( channel ), 5.0);
423 /* ao unipolar linearity, low */
424 o = setup->observables + ni_ao_unip_low_linearity( channel );
425 assert( o->name == NULL );
426 asprintf( &o->name, "ao %i, unipolar linearity (low), low gain", channel );
427 o->preobserve_insn = po_tmpl;
428 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
429 o->preobserve_insn.data = o->preobserve_data;
430 o->observe_insn = tmpl;
431 o->observe_insn.chanspec =
432 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
433 | CR_ALT_SOURCE | CR_ALT_FILTER;
434 o->reference_source = REF_DAC_GND( channel );
435 set_target( setup, ni_ao_unip_low_linearity( channel ), 1.0);
440 static void ni_setup_observables( calibration_setup_t *setup )
444 int bipolar_highgain;
445 int unipolar_lowgain;
446 int unipolar_highgain;
447 double voltage_reference;
450 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
451 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
452 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
453 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
455 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
456 ni_board( setup )->ref_eeprom_msb >= 0 )
458 voltage_reference = ni_get_reference( setup,
459 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
462 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
463 "correction. This might be fixable if you send us an eeprom dump\n"
464 "(see the demo/eeprom_dump program).\n");
465 voltage_reference = 5.0;
468 memset(&tmpl,0,sizeof(tmpl));
469 tmpl.insn = INSN_READ;
471 tmpl.subdev = setup->ad_subdev;
473 setup->n_observables = ni_num_observables;
475 /* 0 offset, low gain */
476 o = setup->observables + ni_zero_offset_low;
477 o->name = "ai, bipolar zero offset, low gain";
478 o->observe_insn = tmpl;
479 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
480 | CR_ALT_SOURCE | CR_ALT_FILTER;
481 o->reference_source = REF_GND_GND;
484 /* 0 offset, high gain */
485 o = setup->observables + ni_zero_offset_high;
486 o->name = "ai, bipolar zero offset, high gain";
487 o->observe_insn = tmpl;
488 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
489 | CR_ALT_SOURCE | CR_ALT_FILTER;
490 o->reference_source = REF_GND_GND;
493 /* voltage reference */
494 o = setup->observables + ni_reference_low;
495 o->name = "ai, bipolar voltage reference, low gain";
496 o->observe_insn = tmpl;
497 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
498 | CR_ALT_SOURCE | CR_ALT_FILTER;
499 o->reference_source = REF_CALSRC_GND;
500 o->target = voltage_reference;
502 if(unipolar_lowgain>=0){
503 o = setup->observables + ni_unip_zero_offset_low;
504 o->name = "ai, unipolar zero offset, low gain";
505 o->observe_insn = tmpl;
506 o->observe_insn.chanspec =
507 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
508 | CR_ALT_SOURCE | CR_ALT_FILTER;
509 o->reference_source = REF_GND_GND;
510 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
512 o = setup->observables + ni_unip_reference_low;
513 o->name = "ai, unipolar voltage reference, low gain";
514 o->observe_insn = tmpl;
515 o->observe_insn.chanspec =
516 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
517 | CR_ALT_SOURCE | CR_ALT_FILTER;
518 o->reference_source = REF_CALSRC_GND;
519 o->target = voltage_reference;
522 if(unipolar_highgain >= 0)
524 o = setup->observables + ni_unip_zero_offset_high;
525 o->name = "ai, unipolar zero offset, high gain";
526 o->observe_insn = tmpl;
527 o->observe_insn.chanspec =
528 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
529 | CR_ALT_SOURCE | CR_ALT_FILTER;
530 o->reference_source = REF_GND_GND;
531 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
534 if(setup->da_subdev >= 0)
535 ni_setup_ao_observables( setup );
538 /* for +-50V and +-20V ranges, the reference source goes 0V
539 * to 50V instead of 0V to 5V */
540 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
544 bits = 200.0 * ( *voltage / reference );
545 if( bits > 200 ) bits = 200;
546 if( bits < 0 ) bits = 0;
548 *voltage = reference * ( bits / 200.0 );
552 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
554 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
557 static void reference_target_611x( calibration_setup_t *setup,
558 observable *o, double master_reference, unsigned int range )
560 int cal_gain_reg_bits;
563 comedi_range *range_ptr;
565 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
566 assert( range_ptr != NULL );
567 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
568 else reference = master_reference;
569 target = range_ptr->max * 0.8;
571 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
573 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
577 static void ni_setup_observables_611x( calibration_setup_t *setup )
582 double master_reference;
584 int num_ai_channels, num_ai_ranges;
585 static const int num_ao_channels = 2;
587 setup->sv_settling_time_ns = 10000000;
588 setup->sv_order = 14;
590 master_reference = ni_get_reference( setup,
591 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
593 memset(&tmpl,0,sizeof(tmpl));
594 tmpl.insn = INSN_READ;
596 tmpl.subdev = setup->ad_subdev;
598 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
599 assert( num_ai_channels >= 0 );
600 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
601 assert( num_ai_ranges >= 0 );
603 for( channel = 0; channel < num_ai_channels; channel++ )
605 for( range = 0; range < num_ai_ranges; range++ )
608 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
609 assert( o->name == NULL );
610 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
612 o->observe_insn = tmpl;
613 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
614 | CR_ALT_SOURCE | CR_ALT_FILTER;
615 o->reference_source = REF_GND_GND;
618 /* voltage reference */
619 o = setup->observables + ni_reference_611x( setup, channel, range );
620 assert( o->name == NULL );
621 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
623 o->observe_insn = tmpl;
624 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
625 | CR_ALT_SOURCE | CR_ALT_FILTER;
626 reference_target_611x( setup, o, master_reference, range );
630 memset(&po_tmpl,0,sizeof(po_tmpl));
631 po_tmpl.insn = INSN_WRITE;
633 po_tmpl.subdev = setup->da_subdev;
635 for( channel = 0; channel < num_ao_channels; channel ++ )
637 static const int ai_range_for_ao = 2;
640 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
641 assert( o->name == NULL );
642 asprintf( &o->name, "ao ch %i, zero offset", channel );
643 o->preobserve_insn = po_tmpl;
644 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
645 o->preobserve_insn.data = o->preobserve_data;
646 o->observe_insn = tmpl;
647 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
648 | CR_ALT_SOURCE | CR_ALT_FILTER;
649 o->reference_source = REF_DAC_GND( channel );
650 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
653 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
654 assert( o->name == NULL );
655 asprintf( &o->name, "ao ch %i, reference voltage", channel );
656 o->preobserve_insn = po_tmpl;
657 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
658 o->preobserve_insn.data = o->preobserve_data;
659 o->observe_insn = tmpl;
660 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
661 | CR_ALT_SOURCE | CR_ALT_FILTER;
662 o->reference_source = REF_DAC_GND( channel );
663 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
666 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
669 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
671 ni_caldac_layout_t layout;
673 init_ni_caldac_layout( &layout );
674 layout.adc_pregain_offset = 8;
675 layout.adc_postgain_offset = 2;
677 layout.adc_gain_fine = 1;
679 return cal_ni_generic( setup, &layout );
682 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
684 ni_caldac_layout_t layout;
686 init_ni_caldac_layout( &layout );
687 layout.adc_pregain_offset = 8;
688 layout.adc_postgain_offset = 2;
690 layout.adc_gain_fine = 1;
691 layout.dac_offset[ 0 ] = 6;
692 layout.dac_gain[ 0 ] = 4;
693 layout.dac_offset[ 1 ] = 7;
694 layout.dac_gain[ 1 ] = 5;
696 return cal_ni_generic( setup, &layout );
699 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
701 ni_caldac_layout_t layout;
703 init_ni_caldac_layout( &layout );
704 layout.adc_pregain_offset = 8;
705 layout.adc_postgain_offset = 2;
706 layout.adc_postgain_offset_fine = 3;
708 layout.adc_gain_fine = 1;
709 layout.dac_offset[ 0 ] = 6;
710 layout.dac_gain[ 0 ] = 4;
711 layout.dac_offset[ 1 ] = 7;
712 layout.dac_gain[ 1 ] = 5;
714 return cal_ni_generic( setup, &layout );
717 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
719 ni_caldac_layout_t layout;
721 init_ni_caldac_layout( &layout );
722 layout.adc_pregain_offset = 0;
723 layout.adc_postgain_offset = 1;
725 layout.adc_unip_offset = 2;
726 layout.dac_offset[0] = 5;
727 layout.dac_gain[0] = 6;
728 layout.dac_linearity[0] = 4;
729 layout.dac_offset[1] = 8;
730 layout.dac_gain[1] = 9;
731 layout.dac_linearity[1] = 7;
733 return cal_ni_generic( setup, &layout );
736 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
738 return cal_ni_at_mio_16e_1(setup);
741 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
743 ni_caldac_layout_t layout;
745 init_ni_caldac_layout( &layout );
746 layout.adc_pregain_offset = 0;
747 layout.adc_postgain_offset = 1;
748 layout.adc_unip_offset = 2;
750 layout.dac_offset[ 0 ] = 5;
751 layout.dac_gain[ 0 ] = 6;
752 layout.dac_linearity[ 0 ] = 4;
753 layout.dac_offset[ 1 ] = 8;
754 layout.dac_gain[ 1 ] = 9;
755 layout.dac_linearity[ 1 ] = 7;
757 return cal_ni_generic( setup, &layout );
760 static int cal_ni_pci_6014(calibration_setup_t *setup)
762 ni_caldac_layout_t layout;
764 init_ni_caldac_layout( &layout );
765 layout.adc_pregain_offset = 0;
766 layout.adc_postgain_offset = 4;
767 layout.adc_pregain_offset_fine = 8;
769 layout.dac_offset[0] = 6;
770 layout.dac_offset_fine[0] = 10;
771 layout.dac_gain[0] = 7;
772 layout.dac_gain_fine[0] = 11;
773 layout.dac_offset[1] = 9;
774 layout.dac_offset_fine[1] = 1;
775 layout.dac_gain[1] = 3;
776 layout.dac_gain_fine[1] = 5;
777 return cal_ni_generic( setup, &layout );
780 static int cal_ni_pci_6032e(calibration_setup_t *setup)
782 ni_caldac_layout_t layout;
784 init_ni_caldac_layout( &layout );
785 layout.adc_pregain_offset = 8;
786 layout.adc_postgain_offset = 2;
787 layout.adc_postgain_offset_fine = 3;
789 layout.adc_gain_fine = 1;
791 return cal_ni_generic( setup, &layout );
794 static int cal_ni_pci_6034e(calibration_setup_t *setup)
796 ni_caldac_layout_t layout;
798 init_ni_caldac_layout( &layout );
799 layout.adc_pregain_offset = 0;
800 layout.adc_pregain_offset_fine = 8;
801 layout.adc_postgain_offset = 4;
804 return cal_ni_generic( setup, &layout );
807 static int cal_ni_pci_6035e(calibration_setup_t *setup)
809 /* this is for the ad8804_debug caldac */
810 ni_caldac_layout_t layout;
812 init_ni_caldac_layout( &layout );
813 layout.adc_pregain_offset = 0;
814 layout.adc_pregain_offset_fine = 8;
815 layout.adc_postgain_offset = 4;
817 layout.dac_offset[ 0 ] = 6;
818 layout.dac_gain[ 0 ] = 11;
819 layout.dac_linearity[ 0 ] = 10;
820 layout.dac_offset[ 1 ] = 9;
821 layout.dac_gain[ 1 ] = 5;
822 layout.dac_linearity[ 1 ] = 1;
824 return cal_ni_generic( setup, &layout );
827 static int cal_ni_pci_6036e(calibration_setup_t *setup)
829 ni_caldac_layout_t layout;
831 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
833 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
834 "for this calibration to work properly\n" );
837 /* this is for the ad8804_debug caldac */
838 init_ni_caldac_layout( &layout );
839 layout.adc_pregain_offset = 0;
840 layout.adc_postgain_offset = 4;
841 layout.adc_pregain_offset_fine = 8;
843 layout.dac_offset[ 0 ] = 6;
844 layout.dac_gain[ 0 ] = 7;
845 layout.dac_gain_fine[ 0 ] = 11;
846 layout.dac_linearity[ 0 ] = 10;
847 layout.dac_offset[ 1 ] = 9;
848 layout.dac_gain[ 1 ] = 3;
849 layout.dac_gain_fine[ 1 ] = 5;
850 layout.dac_linearity[ 1 ] = 1;
852 return cal_ni_generic( setup, &layout );
855 static int cal_ni_pci_6071e(calibration_setup_t *setup)
857 ni_caldac_layout_t layout;
859 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
861 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
862 "for this calibration to work properly\n" );
865 init_ni_caldac_layout( &layout );
866 layout.adc_pregain_offset = 8;
867 layout.adc_postgain_offset = 4;
868 layout.adc_unip_offset = 7;
870 layout.dac_offset[ 0 ] = 6;
871 layout.dac_gain[ 0 ] = 11;
872 layout.dac_linearity[ 0 ] = 10;
873 layout.dac_offset[ 1 ] = 9;
874 layout.dac_gain[ 1 ] = 5;
875 layout.dac_linearity[ 1 ] = 1;
876 return cal_ni_generic( setup, &layout );
879 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
881 ni_caldac_layout_t layout;
883 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
885 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
886 "for this calibration to work properly\n" );
889 init_ni_caldac_layout( &layout );
890 layout.adc_pregain_offset = 0;
891 layout.adc_pregain_offset_fine = 8;
892 layout.adc_postgain_offset = 4;
894 layout.dac_offset[ 0 ] = 6;
895 layout.dac_gain[ 0 ] = 11;
896 layout.dac_linearity[ 0 ] = 10;
897 layout.dac_offset[ 1 ] = 9;
898 layout.dac_gain[ 1 ] = 5;
899 layout.dac_linearity[ 1 ] = 1;
900 return cal_ni_generic( setup, &layout );
903 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
905 ni_caldac_layout_t layout;
907 if(comedi_get_version_code(setup->dev) <= COMEDI_VERSION_CODE(0, 7, 68))
909 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
910 "for this calibration to work properly\n" );
912 init_ni_caldac_layout( &layout );
913 layout.adc_pregain_offset = 0;
914 layout.adc_pregain_offset_fine = 8;
915 layout.adc_postgain_offset = 4;
917 layout.adc_unip_offset = 7;
918 layout.dac_offset[ 0 ] = 6;
919 layout.dac_gain[ 0 ] = 11;
920 layout.dac_linearity[ 0 ] = 10;
921 layout.dac_offset[ 1 ] = 9;
922 layout.dac_gain[ 1 ] = 5;
923 layout.dac_linearity[1] = 1;
924 return cal_ni_generic( setup, &layout );
927 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
929 ni_caldac_layout_t layout;
931 init_ni_caldac_layout( &layout );
932 layout.adc_pregain_offset = 8;
933 layout.adc_postgain_offset = 2;
935 layout.adc_gain_fine = 1;
936 layout.adc_unip_offset = 7;
937 layout.dac_offset[ 0 ] = 6;
938 layout.dac_gain[ 0 ] = 4;
939 layout.dac_offset[ 1 ] = 7;
940 layout.dac_gain[ 1 ] = 5;
942 return cal_ni_generic( setup, &layout );
945 static int cal_ni_pci_6023e(calibration_setup_t *setup)
947 /* for comedi-0.7.65 */
948 ni_caldac_layout_t layout;
950 init_ni_caldac_layout( &layout );
951 layout.adc_pregain_offset = 8; /* possibly wrong */
952 layout.adc_pregain_offset_fine = 0;
953 layout.adc_postgain_offset = 4;
956 return cal_ni_generic( setup, &layout );
959 static int cal_ni_pci_6024e(calibration_setup_t *setup)
961 ni_caldac_layout_t layout;
963 init_ni_caldac_layout( &layout );
964 layout.adc_pregain_offset = 0;
965 layout.adc_postgain_offset = 4;
966 layout.adc_pregain_offset_fine = 8;
968 layout.dac_offset[ 0 ] = 6;
969 layout.dac_gain[ 0 ] = 11;
970 layout.dac_linearity[ 0 ] = 10;
971 layout.dac_offset[ 1 ] = 9;
972 layout.dac_gain[ 1 ] = 5;
973 layout.dac_linearity[ 1 ] = 1;
975 return cal_ni_generic( setup, &layout );
978 static int cal_ni_pci_6025e(calibration_setup_t *setup)
980 ni_caldac_layout_t layout;
982 init_ni_caldac_layout( &layout );
983 layout.adc_pregain_offset = 0;
984 layout.adc_postgain_offset = 4;
985 layout.adc_pregain_offset_fine = 8;
987 layout.dac_offset[ 0 ] = 6;
988 layout.dac_gain[ 0 ] = 11;
989 layout.dac_linearity[ 0 ] = 10;
990 layout.dac_offset[ 1 ] = 9;
991 layout.dac_gain[ 1 ] = 5;
992 layout.dac_linearity[ 1 ] = 1;
994 return cal_ni_generic( setup, &layout );
997 static int cal_ni_pci_6052e(calibration_setup_t *setup)
1000 * This board has noisy caldacs
1002 * The NI documentation says (true mb88341 addressing):
1003 * 0, 8 AI pregain (coarse, fine)
1005 * 2, 10 AI reference
1006 * 14, 7 AI unipolar offset
1009 * 8, 4 AO0 reference
1012 * 10, 6 AO1 reference
1015 * For us, these map to (ad8804 channels)
1017 * 0, 1 AI pregain (coarse, fine)
1020 * 7 AI unipolar offset
1023 * 1, 2 AO0 reference
1026 * 5, 6 AO1 reference
1029 * or, with mb88341 channels
1032 * 7, 3 AO0 reference
1035 * 9, 5 AO1 reference
1039 ni_caldac_layout_t layout;
1041 init_ni_caldac_layout( &layout );
1042 layout.adc_pregain_offset = 0;
1043 layout.adc_postgain_offset = 2;
1044 layout.adc_gain = 4;
1045 layout.adc_unip_offset = 6;
1046 layout.adc_unip_offset_fine = 7;
1047 layout.adc_pregain_offset_fine = 1;
1048 layout.adc_postgain_offset_fine = 3;
1049 layout.adc_gain_fine = 5;
1051 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1052 "for this calibration to work properly\n" );
1053 /* this works when the first two caldacs are ad8804_debug */
1054 layout.dac_offset[ 0 ] = 16 + 3;
1055 layout.dac_gain[ 0 ] = 16 + 1;
1056 layout.dac_gain_fine[ 0 ] = 16 + 2;
1057 layout.dac_linearity[ 0 ] = 16 + 0;
1058 layout.dac_offset[ 1 ] = 16 + 7;
1059 layout.dac_gain[ 1 ] = 16 + 5;
1060 layout.dac_gain_fine[ 1 ] = 16 + 6;
1061 layout.dac_linearity[ 1 ] = 16 + 4;
1063 return cal_ni_generic( setup, &layout );
1066 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
1068 ni_caldac_layout_t layout;
1070 init_ni_caldac_layout( &layout );
1071 layout.adc_pregain_offset = 0;
1072 layout.adc_postgain_offset = 1;
1073 layout.adc_gain = 3;
1074 layout.adc_unip_offset = 2;
1076 return cal_ni_generic( setup, &layout );
1079 static int adc_offset_611x( unsigned int channel )
1081 return 2 * channel + 2;
1083 static int adc_gain_611x( unsigned int channel )
1085 return 2 * channel + 1;
1087 static int dac_offset_611x( unsigned int channel )
1089 return 12 + 2 + 2 * channel;
1091 static int dac_gain_611x( unsigned int channel )
1093 return 12 + 1 + 2 * channel;
1095 static int cal_ni_pci_611x( calibration_setup_t *setup )
1097 generic_layout_t layout;
1099 init_generic_layout( &layout );
1100 layout.adc_offset = adc_offset_611x;
1101 layout.adc_gain = adc_gain_611x;
1102 layout.dac_offset = dac_offset_611x;
1103 layout.dac_gain = dac_gain_611x;
1104 layout.adc_high_observable = ni_reference_611x;
1105 layout.adc_ground_observable = ni_zero_offset_611x;
1106 layout.dac_high_observable = ni_ao_reference_611x;
1107 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1109 return generic_cal_by_channel_and_range( setup, &layout );
1112 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1114 ni_caldac_layout_t layout;
1116 init_ni_caldac_layout( &layout );
1117 layout.adc_pregain_offset = 8;
1118 layout.adc_postgain_offset = 4;
1119 layout.adc_gain = 2;
1120 layout.adc_unip_offset = 7;
1121 layout.dac_offset[ 0 ] = 6;
1122 layout.dac_gain[ 0 ] = 11;
1123 layout.dac_linearity[ 0 ] = 10;
1124 layout.dac_offset[ 1 ] = 9;
1125 layout.dac_gain[ 1 ] = 5;
1126 layout.dac_linearity[ 1 ] = 1;
1128 return cal_ni_generic( setup, &layout );
1131 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1133 ni_caldac_layout_t layout;
1135 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1137 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1138 "for this calibration to work properly\n" );
1140 init_ni_caldac_layout( &layout );
1141 layout.adc_pregain_offset = 8;
1142 layout.adc_postgain_offset = 4;
1143 layout.adc_gain = 2;
1144 layout.adc_unip_offset = 7;
1145 layout.dac_offset[ 0 ] = 6;
1146 layout.dac_gain[ 0 ] = 11;
1147 layout.dac_linearity[ 0 ] = 10;
1148 layout.dac_offset[ 1 ] = 9;
1149 layout.dac_gain[ 1 ] = 5;
1150 layout.dac_linearity[ 1 ] = 1;
1152 return cal_ni_generic( setup, &layout );
1155 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1157 ni_caldac_layout_t layout;
1159 init_ni_caldac_layout( &layout );
1161 layout.adc_pregain_offset = 0;
1162 layout.adc_postgain_offset = 4;
1163 layout.adc_gain = 2;
1164 //layout.adc_unip_offset = 7;
1165 layout.dac_offset[ 0 ] = 6;
1166 layout.dac_gain[ 0 ] = 3;
1167 //layout.dac_linearity[ 0 ] = 10;
1168 layout.dac_offset[ 1 ] = 1;
1169 layout.dac_gain[ 1 ] = 5;
1170 //layout.dac_linearity[ 1 ] = 1;
1172 return cal_ni_generic( setup, &layout );
1175 static int cal_ni_daqcard_6036e( calibration_setup_t *setup )
1177 ni_caldac_layout_t layout;
1179 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 68 ) )
1181 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1182 "for this calibration to work properly\n" );
1185 init_ni_caldac_layout( &layout );
1187 layout.adc_pregain_offset = 0;
1188 layout.adc_pregain_offset_fine = 8;
1189 layout.adc_postgain_offset = 4;
1190 layout.adc_gain = 2;
1192 layout.dac_offset[0] = 6;
1193 layout.dac_gain[0] = 7;
1194 layout.dac_gain_fine[ 0 ] = 11;
1195 layout.dac_linearity[0] = 10;
1197 layout.dac_offset[ 1 ] = 9;
1198 layout.dac_gain[ 1 ] = 3;
1199 layout.dac_gain_fine[ 1 ] = 5;
1200 layout.dac_linearity[1] = 1;
1202 return cal_ni_generic( setup, &layout );
1205 static int cal_ni_at_mio_64e_3( calibration_setup_t *setup )
1207 ni_caldac_layout_t layout;
1209 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 68 ) )
1211 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1212 "for this calibration to work properly\n" );
1215 init_ni_caldac_layout( &layout );
1217 layout.adc_pregain_offset = 8;
1218 layout.adc_postgain_offset = 4;
1219 layout.adc_gain = 2;
1221 layout.dac_offset[0] = 6;
1222 layout.dac_gain[0] = 14;
1223 layout.dac_linearity[0] = 10;
1225 layout.dac_offset[ 1 ] = 9;
1226 layout.dac_gain[ 1 ] = 5;
1227 layout.dac_linearity[1] = 1;
1229 return cal_ni_generic( setup, &layout );
1232 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1233 const ni_caldac_layout_t *layout, unsigned int range )
1237 if( setup->old_calibration == NULL )
1239 reset_caldac( setup, layout->adc_pregain_offset );
1240 reset_caldac( setup, layout->adc_postgain_offset );
1241 reset_caldac( setup, layout->adc_gain );
1242 reset_caldac( setup, layout->adc_pregain_offset_fine );
1243 reset_caldac( setup, layout->adc_postgain_offset_fine );
1244 reset_caldac( setup, layout->adc_gain_fine );
1245 reset_caldac( setup, layout->adc_unip_offset );
1246 reset_caldac( setup, layout->adc_unip_offset_fine );
1249 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1250 0, range, AREF_GROUND, setup->old_calibration );
1253 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1254 reset_caldac( setup, layout->adc_pregain_offset );
1255 reset_caldac( setup, layout->adc_postgain_offset );
1256 reset_caldac( setup, layout->adc_gain );
1257 reset_caldac( setup, layout->adc_pregain_offset_fine );
1258 reset_caldac( setup, layout->adc_postgain_offset_fine );
1259 reset_caldac( setup, layout->adc_gain_fine );
1260 reset_caldac( setup, layout->adc_unip_offset );
1261 reset_caldac( setup, layout->adc_unip_offset_fine );
1266 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1267 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1271 if( setup->da_subdev < 0 ) return;
1273 if( setup->old_calibration == NULL )
1275 reset_caldac( setup, layout->dac_offset[ channel ] );
1276 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1277 reset_caldac( setup, layout->dac_gain[ channel ] );
1278 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1279 reset_caldac( setup, layout->dac_linearity[ channel ] );
1282 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1283 channel, range, AREF_GROUND, setup->old_calibration );
1286 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1287 reset_caldac( setup, layout->dac_offset[ channel ] );
1288 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1289 reset_caldac( setup, layout->dac_gain[ channel ] );
1290 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1291 reset_caldac( setup, layout->dac_linearity[ channel ] );
1296 static void prep_adc_for_dac( calibration_setup_t *setup, int observable )
1298 unsigned int adc_range;
1301 if( observable < 0 ) return;
1303 chanspec = setup->observables[ observable ].observe_insn.chanspec;
1304 adc_range = CR_RANGE( chanspec );
1306 comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1307 0, adc_range, 0, setup->new_calibration );
1310 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1312 comedi_calibration_setting_t *current_cal;
1316 int ai_unipolar_lowgain, ai_bipolar_lowgain;
1318 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
1319 assert( num_ai_ranges > 0 );
1321 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
1322 ai_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev );
1324 prep_adc_caldacs_generic( setup, layout, ai_bipolar_lowgain );
1326 current_cal = sc_alloc_calibration_setting( setup );
1327 current_cal->subdevice = setup->ad_subdev;
1328 reset_caldac( setup, layout->adc_gain_fine );
1329 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1330 ni_reference_low, layout->adc_gain );
1331 reset_caldac( setup, layout->adc_postgain_offset_fine );
1332 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1333 ni_zero_offset_high, layout->adc_postgain_offset );
1334 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1335 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1336 reset_caldac( setup, layout->adc_pregain_offset_fine );
1337 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1338 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1339 ni_reference_low, layout->adc_gain_fine );
1340 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1341 layout->adc_pregain_offset_fine );
1342 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1343 sc_push_aref( current_cal, SC_ALL_AREFS );
1344 if( layout->adc_unip_offset >= 0 )
1346 sc_push_range( current_cal, SC_ALL_RANGES );
1349 for( range = 0; range < num_ai_ranges; range++ )
1351 if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
1352 sc_push_range( current_cal, range );
1356 /* do seperate unipolar calibration if appropriate */
1357 if( ai_unipolar_lowgain >= 0 )
1359 current_cal = sc_alloc_calibration_setting( setup );
1360 current_cal->subdevice = setup->ad_subdev;
1361 if( layout->adc_unip_offset >= 0 )
1363 reset_caldac( setup, layout->adc_unip_offset_fine );
1364 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1365 layout->adc_unip_offset );
1366 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1367 layout->adc_unip_offset_fine );
1368 /* if we don't have a unipolar offset caldac, do a fully
1369 * independent calibration for unipolar ranges */
1372 prep_adc_caldacs_generic( setup, layout, ai_unipolar_lowgain );
1373 generic_peg( setup, ni_unip_zero_offset_low,
1374 layout->adc_pregain_offset, 1 );
1375 generic_peg( setup, ni_unip_zero_offset_low,
1376 layout->adc_postgain_offset, 1 );
1377 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1378 ni_unip_reference_low, layout->adc_gain );
1379 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1380 ni_unip_zero_offset_high, layout->adc_postgain_offset );
1381 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1382 ni_unip_zero_offset_high, layout->adc_postgain_offset_fine );
1383 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1384 layout->adc_pregain_offset );
1385 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1386 ni_unip_reference_low, layout->adc_gain_fine );
1387 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1388 layout->adc_pregain_offset_fine );
1390 for( range = 0; range < num_ai_ranges; range++ )
1392 if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
1393 sc_push_range( current_cal, range );
1395 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1396 sc_push_aref( current_cal, SC_ALL_AREFS );
1398 if( setup->da_subdev >= 0 && setup->do_output )
1400 unsigned int channel, range;
1401 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1402 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1405 for( channel = 0; channel < 2; channel++ )
1407 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1408 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1409 prep_adc_for_dac( setup, ni_ao_reference( channel ) );
1411 current_cal = sc_alloc_calibration_setting( setup );
1412 current_cal->subdevice = setup->da_subdev;
1413 generic_do_linearity( setup, current_cal, ni_ao_zero_offset( channel ),
1414 ni_ao_mid_linearity( channel ), ni_ao_reference( channel ),
1415 layout->dac_linearity[ channel ] );
1416 reset_caldac(setup, layout->dac_offset_fine[channel]);
1417 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1418 layout->dac_offset[ channel ] );
1419 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1420 layout->dac_offset_fine[ channel ] );
1421 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1422 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1423 layout->dac_gain[ channel ] );
1424 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1425 layout->dac_gain_fine[ channel ] );
1426 sc_push_channel( current_cal, channel );
1427 for( range = 0; range < num_ao_ranges; range++ )
1429 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1430 sc_push_range( current_cal, range );
1432 sc_push_aref( current_cal, SC_ALL_AREFS );
1434 if( ao_unipolar_lowgain >= 0 )
1436 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1438 current_cal = sc_alloc_calibration_setting( setup );
1439 current_cal->subdevice = setup->da_subdev;
1440 generic_do_linearity( setup, current_cal, ni_ao_unip_low_linearity( channel ),
1441 ni_ao_unip_mid_linearity( channel ), ni_ao_unip_reference( channel ),
1442 layout->dac_linearity[ channel ] );
1443 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1444 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1445 layout->dac_offset[ channel ] );
1446 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1447 layout->dac_offset_fine[ channel ] );
1448 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1449 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1450 layout->dac_gain[ channel ] );
1451 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1452 layout->dac_gain_fine[ channel ] );
1453 sc_push_channel( current_cal, channel );
1454 for( range = 0; range < num_ao_ranges; range++ )
1456 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1457 sc_push_range( current_cal, range );
1459 sc_push_aref( current_cal, SC_ALL_AREFS );
1464 retval = write_calibration_file( setup );
1469 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1475 lsb=read_eeprom( setup, lsb_loc );
1476 msb=read_eeprom( setup, msb_loc );
1477 assert( lsb >=0 && msb >= 0 );
1478 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1480 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1481 ref=5.000+1.0e-6*uv;
1482 DPRINT(0, "resulting reference voltage: %g\n", ref );
1483 if( fabs( ref - 5.0 ) > 0.005 )
1484 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1485 "from 5V. Possible bad eeprom address?\n" );
1491 NI 671x and 673x support
1494 static const int channels_per_ad8804 = 16;
1496 static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel)
1498 int ad8804_gain_channels[4] = {8, 2, 11, 5};
1499 int caldac_channel = ad8804_gain_channels[ao_channel % 4];
1500 int caldac_index = ao_channel / 4;
1501 /* just guessing that second ad8804 is works for ao channels 4-7
1502 * the same as the first ad8804 works for ao channels 0-3 */
1503 return caldac_index * channels_per_ad8804 + caldac_channel;
1505 static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel)
1507 int ad8804_linearity_channels[4] = {4, 10, 1, 0};
1508 int caldac_channel = ad8804_linearity_channels[ao_channel % 4];
1509 int caldac_index = ao_channel / 4;
1511 return caldac_index * channels_per_ad8804 + caldac_channel;
1513 static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel)
1515 int ad8804_offset_channels[4] = {7, 6, 9, 3};
1516 int caldac_channel = ad8804_offset_channels[ao_channel % 4];
1517 int caldac_index = ao_channel / 4;
1519 return caldac_index * channels_per_ad8804 + caldac_channel;
1522 static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup,
1523 unsigned int channel, unsigned int ao_range )
1525 return 3 * channel + 0;
1528 static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup,
1529 unsigned int channel, unsigned int ao_range )
1531 return 3 * channel + 1;
1534 static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup,
1535 unsigned int channel, unsigned int ao_range )
1537 return 3 * channel + 2;
1540 static const double ni67xx_unitless_adc_offset = 0.5;
1542 /* determine conversion factor between actual voltage and
1543 * interval [0,1) returned by reads from the calibration adc
1546 static double ni67xx_unitless_adc_slope(calibration_setup_t *setup)
1548 double reference_in_volts;
1549 double reference_unitless;
1553 comedi_range *range;
1554 static const int maxdata = 0x10000;
1557 if(ni_board(setup)->ref_eeprom_lsb >= 0 &&
1558 ni_board(setup)->ref_eeprom_msb >= 0)
1560 reference_in_volts = ni_get_reference(setup,
1561 ni_board(setup)->ref_eeprom_lsb, ni_board(setup)->ref_eeprom_msb );
1564 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
1565 "correction. This might be fixable if you send us an eeprom dump\n"
1566 "(see the demo/eeprom_dump program).\n");
1567 reference_in_volts = 5.0;
1570 memset(&insn, 0, sizeof(insn));
1571 insn.insn = INSN_READ;
1573 insn.subdev = setup->ad_subdev;
1575 insn.chanspec = CR_PACK(0, 0, AREF_GROUND) | CR_ALT_SOURCE;
1576 retval = comedi_do_insn(setup->dev, &insn);
1577 assert(retval >= 0);
1579 range = comedi_get_range(setup->dev, setup->ad_subdev, 0, 0);
1581 reference_unitless = comedi_to_phys(data, range, maxdata);
1583 slope = (reference_unitless - ni67xx_unitless_adc_offset) / reference_in_volts;
1588 /* calibration adc uses RANGE_UNKNOWN, so it will return a value from
1589 0.0 to 1.0 instead of a voltage, so we need to renormalize. */
1590 static void ni67xx_set_target( calibration_setup_t *setup, int obs, double target, double slope)
1592 set_target(setup, obs, target);
1593 /* convert target from volts to interval [0,1) which calibration
1595 setup->observables[obs].target *= slope;
1596 setup->observables[obs].target += ni67xx_unitless_adc_offset;
1599 static void ni67xx_setup_observables( calibration_setup_t *setup )
1601 comedi_insn tmpl, po_tmpl;
1603 int num_ao_channels;
1607 slope = ni67xx_unitless_adc_slope(setup);
1609 /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */
1610 setup->sv_order = 1;
1612 num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev);
1613 assert(num_ao_channels >= 0);
1615 memset( &tmpl, 0, sizeof(tmpl) );
1616 tmpl.insn = INSN_READ;
1618 tmpl.subdev = setup->ad_subdev;
1620 memset( &po_tmpl, 0, sizeof(po_tmpl) );
1621 po_tmpl.insn = INSN_WRITE;
1623 po_tmpl.subdev = setup->da_subdev;
1625 setup->n_observables = 0;
1627 for(i = 0; i < num_ao_channels; i++)
1629 o = setup->observables + ni67xx_ao_ground_observable_index( setup,
1631 o->reference_source = -1;
1632 assert( o->name == NULL );
1633 asprintf(&o->name, "dac%i ground, ground referenced", i);
1634 o->preobserve_insn = po_tmpl;
1635 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1636 o->preobserve_insn.data = o->preobserve_data;
1637 o->observe_insn = tmpl;
1638 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1639 ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0, slope);
1640 setup->n_observables++;
1642 o = setup->observables + ni67xx_ao_mid_observable_index( setup,
1644 o->reference_source = -1;
1645 assert( o->name == NULL );
1646 asprintf(&o->name, "dac%i mid, ground referenced", i);
1647 o->preobserve_insn = po_tmpl;
1648 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1649 o->preobserve_insn.data = o->preobserve_data;
1650 o->observe_insn = tmpl;
1651 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1652 ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0, slope);
1653 setup->n_observables++;
1655 o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0);
1656 o->reference_source = -1;
1657 assert( o->name == NULL );
1658 asprintf(&o->name, "dac%i high, ground referenced", i);
1659 o->preobserve_insn = po_tmpl;
1660 o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND );
1661 o->preobserve_insn.data = o->preobserve_data;
1662 o->observe_insn = tmpl;
1663 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1664 ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0, slope);
1665 setup->n_observables++;
1671 static int cal_ni_pci_6711(calibration_setup_t *setup)
1673 generic_layout_t layout;
1675 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE(0, 7, 69))
1677 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1678 "for this calibration to work properly\n" );
1680 init_generic_layout( &layout );
1681 layout.dac_gain = ni67xx_ao_gain_caldac;
1682 layout.dac_linearity = ni67xx_ao_linearity_caldac;
1683 layout.dac_offset = ni67xx_ao_offset_caldac;
1684 layout.dac_high_observable = ni67xx_ao_high_observable_index;
1685 layout.dac_mid_observable = ni67xx_ao_mid_observable_index;
1686 layout.dac_ground_observable = ni67xx_ao_ground_observable_index;
1687 layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 );
1688 return generic_cal_ao(setup, &layout);