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_daqcard_ai_16xe_50(calibration_setup_t *setup);
54 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup);
55 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup);
56 static int cal_ni_pci_6024e(calibration_setup_t *setup);
57 static int cal_ni_pci_6025e(calibration_setup_t *setup);
58 static int cal_ni_pci_6032e(calibration_setup_t *setup);
59 static int cal_ni_pci_6035e(calibration_setup_t *setup);
60 static int cal_ni_pci_6036e(calibration_setup_t *setup);
61 static int cal_ni_pci_6071e(calibration_setup_t *setup);
62 static int cal_ni_pxi_6071e(calibration_setup_t *setup);
63 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup);
64 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup);
65 static int cal_ni_pci_6023e(calibration_setup_t *setup);
66 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup);
67 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup);
68 static int cal_ni_pci_6052e(calibration_setup_t *setup);
69 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup);
70 static int cal_ni_pci_611x(calibration_setup_t *setup);
71 static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup);
72 static int cal_ni_daqcard_6062e(calibration_setup_t *setup);
73 static int cal_ni_daqcard_6024e(calibration_setup_t *setup);
74 static int cal_ni_daqcard_6036e(calibration_setup_t *setup);
75 static int cal_ni_pci_6711(calibration_setup_t *setup);
77 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
79 static struct board_struct boards[]={
80 { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
81 { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
82 { "at-mio-16e-1", STATUS_DONE, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
83 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
84 { "at-mio-16e-10", STATUS_DONE, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
85 { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
86 { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
87 { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
88 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
89 { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
90 { "DAQCard-6036E", STATUS_SOME, cal_ni_daqcard_6036e, ni_setup_observables, 0x1ab, 0x1ac },
91 { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
92 { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
93 { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
94 { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
95 { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
96 { "pci-6014", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
97 { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
98 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
99 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
100 { "pci-6031e", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
101 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
102 { "pci-6033e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1b7, 0x1b8 },
103 { "pci-6034e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
104 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
105 { "pci-6036e", STATUS_DONE, cal_ni_pci_6036e, ni_setup_observables, 0x1ab, 0x1ac },
106 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
107 { "pci-6071e", STATUS_DONE, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
108 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
109 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
110 { "pxi-6025e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
111 { "pxi-6030e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
112 { "pxi-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
113 { "pxi-6040e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
114 { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
115 { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
116 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
117 { "pci-6711", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
118 { "pci-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
119 { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
120 { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
121 { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
122 { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
123 { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
124 { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
126 { "at-mio-64e-3", cal_ni_16e_1 },
129 #define n_boards (sizeof(boards)/sizeof(boards[0]))
131 static const int ni_num_observables = 20;
133 ni_zero_offset_low = 0,
136 ni_unip_zero_offset_low,
137 ni_unip_zero_offset_high,
138 ni_unip_reference_low,
145 ni_ao0_unip_zero_offset,
146 ni_ao0_unip_reference,
147 ni_ao0_unip_low_linearity,
148 ni_ao0_unip_mid_linearity,
149 ni_ao1_unip_zero_offset,
150 ni_ao1_unip_reference,
151 ni_ao1_unip_low_linearity,
152 ni_ao1_unip_mid_linearity,
154 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
156 if( channel ) return ni_ao1_zero_offset;
157 else return ni_ao0_zero_offset;
159 static inline unsigned int ni_ao_reference( unsigned int channel )
161 if( channel ) return ni_ao1_reference;
162 else return ni_ao0_reference;
164 static inline unsigned int ni_ao_mid_linearity( unsigned int channel )
166 if( channel ) return ni_ao1_linearity;
167 else return ni_ao0_linearity;
169 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
171 if( channel ) return ni_ao1_unip_zero_offset;
172 else return ni_ao0_unip_zero_offset;
174 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
176 if( channel ) return ni_ao1_unip_reference;
177 else return ni_ao0_unip_reference;
179 static inline unsigned int ni_ao_unip_low_linearity( unsigned int channel )
181 if( channel ) return ni_ao1_unip_low_linearity;
182 else return ni_ao0_unip_low_linearity;
184 static inline unsigned int ni_ao_unip_mid_linearity( unsigned int channel )
186 if( channel ) return ni_ao1_unip_mid_linearity;
187 else return ni_ao0_unip_mid_linearity;
190 static const int num_ao_observables_611x = 4;
191 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
192 unsigned int channel, unsigned int range ) {
193 assert( range == 0 );
196 static int ni_ao_reference_611x( const calibration_setup_t *setup,
197 unsigned int channel, unsigned int range ) {
198 assert( range == 0 );
199 return 2 * channel + 1;
201 static int ni_zero_offset_611x( const calibration_setup_t *setup,
202 unsigned int channel, unsigned int range ) {
203 return num_ao_observables_611x + 8 * range + 2 * channel;
205 static int ni_reference_611x( const calibration_setup_t *setup,
206 unsigned int channel, unsigned int range ) {
207 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
210 enum reference_sources {
215 REF_CALSRC_CALSRC = 4,
220 static inline unsigned int REF_DAC_GND( unsigned int channel )
222 if( channel ) return REF_DAC1_GND;
223 else return REF_DAC0_GND;
225 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
227 if( channel ) return REF_DAC1_CALSRC;
228 else return REF_DAC0_CALSRC;
231 static struct board_struct* ni_board( calibration_setup_t *setup )
233 return setup->private_data;
238 int adc_pregain_offset;
239 int adc_postgain_offset;
241 int adc_pregain_offset_fine;
242 int adc_postgain_offset_fine;
245 int adc_unip_offset_fine;
248 int dac_gain_fine[ 2 ];
249 int dac_linearity[ 2 ];
250 } ni_caldac_layout_t;
252 static int cal_ni_generic( calibration_setup_t *setup,
253 const ni_caldac_layout_t *layout );
255 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
259 layout->adc_pregain_offset = -1;
260 layout->adc_postgain_offset = -1;
261 layout->adc_gain = -1;
262 layout->adc_unip_offset = -1;
263 layout->adc_unip_offset_fine = -1;
264 layout->adc_pregain_offset_fine = -1;
265 layout->adc_postgain_offset_fine = -1;
266 layout->adc_gain_fine = -1;
267 for( i = 0; i < 2; i++ )
269 layout->dac_offset[ i ] = -1;
270 layout->dac_gain[ i ] = -1;
271 layout->dac_gain_fine[ i ] = -1;
272 layout->dac_linearity[ i ] = -1;
276 int ni_setup( calibration_setup_t *setup , const char *device_name )
280 retval = ni_setup_board( setup, device_name );
281 if( retval < 0 ) return retval;
282 setup_caldacs( setup, setup->caldac_subdev );
287 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
291 for(i = 0; i < n_boards; i++ ){
292 if(!strcmp( device_name, boards[i].name )){
293 setup->status = boards[i].status;
294 setup->do_cal = boards[i].cal;
295 setup->private_data = &boards[ i ];
296 boards[i].setup_observables( setup );
300 if( i == n_boards ) return -1;
304 static void ni_setup_ao_observables( calibration_setup_t *setup )
307 comedi_insn tmpl, po_tmpl;
308 unsigned int channel;
309 int ai_bipolar_lowgain;
310 int ao_bipolar_lowgain;
311 int ao_unipolar_lowgain;
313 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
314 assert(ai_bipolar_lowgain >= 0);
315 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
316 assert(ao_bipolar_lowgain >= 0);
317 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
319 memset(&tmpl,0,sizeof(tmpl));
320 tmpl.insn = INSN_READ;
322 tmpl.subdev = setup->ad_subdev;
324 memset(&po_tmpl, 0, sizeof(po_tmpl));
325 po_tmpl.insn = INSN_WRITE;
327 po_tmpl.subdev = setup->da_subdev;
329 for( channel = 0; channel < 2; channel++ )
332 o = setup->observables + ni_ao_zero_offset( channel );
333 assert( o->name == NULL );
334 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
335 o->preobserve_insn = po_tmpl;
336 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
337 o->preobserve_insn.data = o->preobserve_data;
338 o->observe_insn = tmpl;
339 o->observe_insn.chanspec =
340 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
341 | CR_ALT_SOURCE | CR_ALT_FILTER;
342 o->reference_source = REF_DAC_GND( channel );
343 set_target( setup, ni_ao_zero_offset( channel ),0.0);
346 o = setup->observables + ni_ao_reference( channel );
347 assert( o->name == NULL );
348 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
349 o->preobserve_insn = po_tmpl;
350 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
351 o->preobserve_insn.data = o->preobserve_data;
352 o->observe_insn = tmpl;
353 o->observe_insn.chanspec =
354 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
355 | CR_ALT_SOURCE | CR_ALT_FILTER;
356 o->reference_source = REF_DAC_GND( channel );
357 set_target( setup, ni_ao_reference( channel ),8.0);
359 /* ao linearity, mid */
360 o = setup->observables + ni_ao_mid_linearity( channel );
361 assert( o->name == NULL );
362 asprintf( &o->name, "ao %i, linearity (mid), low gain", channel );
363 o->preobserve_insn = po_tmpl;
364 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
365 o->preobserve_insn.data = o->preobserve_data;
366 o->observe_insn = tmpl;
367 o->observe_insn.chanspec =
368 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
369 | CR_ALT_SOURCE | CR_ALT_FILTER;
370 o->reference_source = REF_DAC_GND( channel );
371 set_target( setup, ni_ao_mid_linearity( channel ),4.0);
373 if( ao_unipolar_lowgain >= 0 )
375 /* ao unipolar zero offset */
376 o = setup->observables + ni_ao_unip_zero_offset( channel );
377 assert( o->name == NULL );
378 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
379 o->preobserve_insn = po_tmpl;
380 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
381 o->preobserve_insn.data = o->preobserve_data;
382 o->observe_insn = tmpl;
383 o->observe_insn.chanspec =
384 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
385 | CR_ALT_SOURCE | CR_ALT_FILTER;
386 o->reference_source = REF_DAC_GND( channel );
387 set_target( setup, ni_ao_unip_zero_offset( channel ),0.0);
389 /* ao unipolar gain */
390 o = setup->observables + ni_ao_unip_reference( channel );
391 assert( o->name == NULL );
392 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
393 o->preobserve_insn = po_tmpl;
394 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
395 o->preobserve_insn.data = o->preobserve_data;
396 o->observe_insn = tmpl;
397 o->observe_insn.chanspec =
398 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
399 | CR_ALT_SOURCE | CR_ALT_FILTER;
400 o->reference_source = REF_DAC_GND( channel );
401 set_target( setup, ni_ao_unip_reference( channel ), 9.0);
403 /* ao unipolar linearity, mid */
404 o = setup->observables + ni_ao_unip_mid_linearity( channel );
405 assert( o->name == NULL );
406 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
407 o->preobserve_insn = po_tmpl;
408 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
409 o->preobserve_insn.data = o->preobserve_data;
410 o->observe_insn = tmpl;
411 o->observe_insn.chanspec =
412 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
413 | CR_ALT_SOURCE | CR_ALT_FILTER;
414 o->reference_source = REF_DAC_GND( channel );
415 set_target( setup, ni_ao_unip_mid_linearity( channel ), 5.0);
417 /* ao unipolar linearity, low */
418 o = setup->observables + ni_ao_unip_low_linearity( channel );
419 assert( o->name == NULL );
420 asprintf( &o->name, "ao %i, unipolar linearity (low), low gain", channel );
421 o->preobserve_insn = po_tmpl;
422 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
423 o->preobserve_insn.data = o->preobserve_data;
424 o->observe_insn = tmpl;
425 o->observe_insn.chanspec =
426 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
427 | CR_ALT_SOURCE | CR_ALT_FILTER;
428 o->reference_source = REF_DAC_GND( channel );
429 set_target( setup, ni_ao_unip_low_linearity( channel ), 1.0);
434 static void ni_setup_observables( calibration_setup_t *setup )
438 int bipolar_highgain;
439 int unipolar_lowgain;
440 int unipolar_highgain;
441 double voltage_reference;
444 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
445 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
446 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
447 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
449 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
450 ni_board( setup )->ref_eeprom_msb >= 0 )
452 voltage_reference = ni_get_reference( setup,
453 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
456 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
457 "correction. This might be fixable if you send us an eeprom dump\n"
458 "(see the demo/eeprom_dump program).\n");
459 voltage_reference = 5.0;
462 memset(&tmpl,0,sizeof(tmpl));
463 tmpl.insn = INSN_READ;
465 tmpl.subdev = setup->ad_subdev;
467 setup->n_observables = ni_num_observables;
469 /* 0 offset, low gain */
470 o = setup->observables + ni_zero_offset_low;
471 o->name = "ai, bipolar zero offset, low gain";
472 o->observe_insn = tmpl;
473 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
474 | CR_ALT_SOURCE | CR_ALT_FILTER;
475 o->reference_source = REF_GND_GND;
478 /* 0 offset, high gain */
479 o = setup->observables + ni_zero_offset_high;
480 o->name = "ai, bipolar zero offset, high gain";
481 o->observe_insn = tmpl;
482 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
483 | CR_ALT_SOURCE | CR_ALT_FILTER;
484 o->reference_source = REF_GND_GND;
487 /* voltage reference */
488 o = setup->observables + ni_reference_low;
489 o->name = "ai, bipolar voltage reference, low gain";
490 o->observe_insn = tmpl;
491 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
492 | CR_ALT_SOURCE | CR_ALT_FILTER;
493 o->reference_source = REF_CALSRC_GND;
494 o->target = voltage_reference;
496 if(unipolar_lowgain>=0){
497 o = setup->observables + ni_unip_zero_offset_low;
498 o->name = "ai, unipolar zero offset, low gain";
499 o->observe_insn = tmpl;
500 o->observe_insn.chanspec =
501 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
502 | CR_ALT_SOURCE | CR_ALT_FILTER;
503 o->reference_source = REF_GND_GND;
504 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
506 o = setup->observables + ni_unip_reference_low;
507 o->name = "ai, unipolar voltage reference, low gain";
508 o->observe_insn = tmpl;
509 o->observe_insn.chanspec =
510 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
511 | CR_ALT_SOURCE | CR_ALT_FILTER;
512 o->reference_source = REF_CALSRC_GND;
513 o->target = voltage_reference;
516 if(unipolar_highgain >= 0)
518 o = setup->observables + ni_unip_zero_offset_high;
519 o->name = "ai, unipolar zero offset, high gain";
520 o->observe_insn = tmpl;
521 o->observe_insn.chanspec =
522 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
523 | CR_ALT_SOURCE | CR_ALT_FILTER;
524 o->reference_source = REF_GND_GND;
525 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
528 if(setup->da_subdev >= 0)
529 ni_setup_ao_observables( setup );
532 /* for +-50V and +-20V ranges, the reference source goes 0V
533 * to 50V instead of 0V to 5V */
534 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
538 bits = 200.0 * ( *voltage / reference );
539 if( bits > 200 ) bits = 200;
540 if( bits < 0 ) bits = 0;
542 *voltage = reference * ( bits / 200.0 );
546 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
548 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
551 static void reference_target_611x( calibration_setup_t *setup,
552 observable *o, double master_reference, unsigned int range )
554 int cal_gain_reg_bits;
557 comedi_range *range_ptr;
559 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
560 assert( range_ptr != NULL );
561 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
562 else reference = master_reference;
563 target = range_ptr->max * 0.8;
565 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
567 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
571 static void ni_setup_observables_611x( calibration_setup_t *setup )
576 double master_reference;
578 int num_ai_channels, num_ai_ranges;
579 static const int num_ao_channels = 2;
581 setup->sv_settling_time_ns = 10000000;
582 setup->sv_order = 14;
584 master_reference = ni_get_reference( setup,
585 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
587 memset(&tmpl,0,sizeof(tmpl));
588 tmpl.insn = INSN_READ;
590 tmpl.subdev = setup->ad_subdev;
592 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
593 assert( num_ai_channels >= 0 );
594 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
595 assert( num_ai_ranges >= 0 );
597 for( channel = 0; channel < num_ai_channels; channel++ )
599 for( range = 0; range < num_ai_ranges; range++ )
602 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
603 assert( o->name == NULL );
604 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
606 o->observe_insn = tmpl;
607 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
608 | CR_ALT_SOURCE | CR_ALT_FILTER;
609 o->reference_source = REF_GND_GND;
612 /* voltage reference */
613 o = setup->observables + ni_reference_611x( setup, channel, range );
614 assert( o->name == NULL );
615 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
617 o->observe_insn = tmpl;
618 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
619 | CR_ALT_SOURCE | CR_ALT_FILTER;
620 reference_target_611x( setup, o, master_reference, range );
624 memset(&po_tmpl,0,sizeof(po_tmpl));
625 po_tmpl.insn = INSN_WRITE;
627 po_tmpl.subdev = setup->da_subdev;
629 for( channel = 0; channel < num_ao_channels; channel ++ )
631 static const int ai_range_for_ao = 2;
634 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
635 assert( o->name == NULL );
636 asprintf( &o->name, "ao ch %i, zero offset", channel );
637 o->preobserve_insn = po_tmpl;
638 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
639 o->preobserve_insn.data = o->preobserve_data;
640 o->observe_insn = tmpl;
641 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
642 | CR_ALT_SOURCE | CR_ALT_FILTER;
643 o->reference_source = REF_DAC_GND( channel );
644 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
647 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
648 assert( o->name == NULL );
649 asprintf( &o->name, "ao ch %i, reference voltage", channel );
650 o->preobserve_insn = po_tmpl;
651 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
652 o->preobserve_insn.data = o->preobserve_data;
653 o->observe_insn = tmpl;
654 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
655 | CR_ALT_SOURCE | CR_ALT_FILTER;
656 o->reference_source = REF_DAC_GND( channel );
657 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
660 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
663 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
665 ni_caldac_layout_t layout;
667 init_ni_caldac_layout( &layout );
668 layout.adc_pregain_offset = 8;
669 layout.adc_postgain_offset = 2;
671 layout.adc_gain_fine = 1;
673 return cal_ni_generic( setup, &layout );
676 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
678 ni_caldac_layout_t layout;
680 init_ni_caldac_layout( &layout );
681 layout.adc_pregain_offset = 8;
682 layout.adc_postgain_offset = 2;
684 layout.adc_gain_fine = 1;
685 layout.dac_offset[ 0 ] = 6;
686 layout.dac_gain[ 0 ] = 4;
687 layout.dac_offset[ 1 ] = 7;
688 layout.dac_gain[ 1 ] = 5;
690 return cal_ni_generic( setup, &layout );
693 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
695 ni_caldac_layout_t layout;
697 init_ni_caldac_layout( &layout );
698 layout.adc_pregain_offset = 8;
699 layout.adc_postgain_offset = 2;
700 layout.adc_postgain_offset_fine = 3;
702 layout.adc_gain_fine = 1;
703 layout.dac_offset[ 0 ] = 6;
704 layout.dac_gain[ 0 ] = 4;
705 layout.dac_offset[ 1 ] = 7;
706 layout.dac_gain[ 1 ] = 5;
708 return cal_ni_generic( setup, &layout );
711 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
713 ni_caldac_layout_t layout;
715 init_ni_caldac_layout( &layout );
716 layout.adc_pregain_offset = 0;
717 layout.adc_postgain_offset = 1;
719 layout.adc_unip_offset = 2;
720 layout.dac_offset[0] = 5;
721 layout.dac_gain[0] = 6;
722 layout.dac_linearity[0] = 4;
723 layout.dac_offset[1] = 8;
724 layout.dac_gain[1] = 9;
725 layout.dac_linearity[1] = 7;
727 return cal_ni_generic( setup, &layout );
730 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
732 return cal_ni_at_mio_16e_1(setup);
735 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
737 ni_caldac_layout_t layout;
739 init_ni_caldac_layout( &layout );
740 layout.adc_pregain_offset = 0;
741 layout.adc_postgain_offset = 1;
742 layout.adc_unip_offset = 2;
744 layout.dac_offset[ 0 ] = 5;
745 layout.dac_gain[ 0 ] = 6;
746 layout.dac_linearity[ 0 ] = 4;
747 layout.dac_offset[ 1 ] = 8;
748 layout.dac_gain[ 1 ] = 9;
749 layout.dac_linearity[ 1 ] = 7;
751 return cal_ni_generic( setup, &layout );
754 static int cal_ni_pci_6032e(calibration_setup_t *setup)
756 ni_caldac_layout_t layout;
758 init_ni_caldac_layout( &layout );
759 layout.adc_pregain_offset = 8;
760 layout.adc_postgain_offset = 2;
761 layout.adc_postgain_offset_fine = 3;
763 layout.adc_gain_fine = 1;
765 return cal_ni_generic( setup, &layout );
768 static int cal_ni_pci_6035e(calibration_setup_t *setup)
770 /* this is for the ad8804_debug caldac */
771 ni_caldac_layout_t layout;
773 init_ni_caldac_layout( &layout );
774 layout.adc_pregain_offset = 0;
775 layout.adc_pregain_offset_fine = 8;
776 layout.adc_postgain_offset = 4;
778 layout.dac_offset[ 0 ] = 6;
779 layout.dac_gain[ 0 ] = 11;
780 layout.dac_linearity[ 0 ] = 10;
781 layout.dac_offset[ 1 ] = 9;
782 layout.dac_gain[ 1 ] = 5;
783 layout.dac_linearity[ 1 ] = 1;
785 return cal_ni_generic( setup, &layout );
788 static int cal_ni_pci_6036e(calibration_setup_t *setup)
790 ni_caldac_layout_t layout;
792 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
794 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
795 "for this calibration to work properly\n" );
798 /* this is for the ad8804_debug caldac */
799 init_ni_caldac_layout( &layout );
800 layout.adc_pregain_offset = 0;
801 layout.adc_postgain_offset = 4;
802 layout.adc_pregain_offset_fine = 8;
804 layout.dac_offset[ 0 ] = 6;
805 layout.dac_gain[ 0 ] = 7;
806 layout.dac_gain_fine[ 0 ] = 11;
807 layout.dac_linearity[ 0 ] = 10;
808 layout.dac_offset[ 1 ] = 9;
809 layout.dac_gain[ 1 ] = 3;
810 layout.dac_gain_fine[ 1 ] = 5;
811 layout.dac_linearity[ 1 ] = 1;
813 return cal_ni_generic( setup, &layout );
816 static int cal_ni_pci_6071e(calibration_setup_t *setup)
818 ni_caldac_layout_t layout;
820 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
822 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
823 "for this calibration to work properly\n" );
826 init_ni_caldac_layout( &layout );
827 layout.adc_pregain_offset = 8;
828 layout.adc_postgain_offset = 4;
829 layout.adc_unip_offset = 7;
831 layout.dac_offset[ 0 ] = 6;
832 layout.dac_gain[ 0 ] = 11;
833 layout.dac_linearity[ 0 ] = 10;
834 layout.dac_offset[ 1 ] = 9;
835 layout.dac_gain[ 1 ] = 5;
836 layout.dac_linearity[ 1 ] = 1;
837 return cal_ni_generic( setup, &layout );
840 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
842 ni_caldac_layout_t layout;
844 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
846 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
847 "for this calibration to work properly\n" );
850 init_ni_caldac_layout( &layout );
851 layout.adc_pregain_offset = 0;
852 layout.adc_pregain_offset_fine = 8;
853 layout.adc_postgain_offset = 4;
855 layout.dac_offset[ 0 ] = 6;
856 layout.dac_gain[ 0 ] = 11;
857 layout.dac_linearity[ 0 ] = 10;
858 layout.dac_offset[ 1 ] = 9;
859 layout.dac_gain[ 1 ] = 5;
860 layout.dac_linearity[ 1 ] = 1;
861 return cal_ni_generic( setup, &layout );
864 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
866 ni_caldac_layout_t layout;
868 if(comedi_get_version_code(setup->dev) <= COMEDI_VERSION_CODE(0, 7, 68))
870 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
871 "for this calibration to work properly\n" );
873 init_ni_caldac_layout( &layout );
874 layout.adc_pregain_offset = 0;
875 layout.adc_pregain_offset_fine = 8;
876 layout.adc_postgain_offset = 4;
878 layout.adc_unip_offset = 7;
879 layout.dac_offset[ 0 ] = 6;
880 layout.dac_gain[ 0 ] = 11;
881 layout.dac_linearity[ 0 ] = 10;
882 layout.dac_offset[ 1 ] = 9;
883 layout.dac_gain[ 1 ] = 5;
884 layout.dac_linearity[1] = 1;
885 return cal_ni_generic( setup, &layout );
888 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
890 ni_caldac_layout_t layout;
892 init_ni_caldac_layout( &layout );
893 layout.adc_pregain_offset = 8;
894 layout.adc_postgain_offset = 2;
896 layout.adc_gain_fine = 1;
897 layout.adc_unip_offset = 7;
898 layout.dac_offset[ 0 ] = 6;
899 layout.dac_gain[ 0 ] = 4;
900 layout.dac_offset[ 1 ] = 7;
901 layout.dac_gain[ 1 ] = 5;
903 return cal_ni_generic( setup, &layout );
906 static int cal_ni_pci_6023e(calibration_setup_t *setup)
908 /* for comedi-0.7.65 */
909 ni_caldac_layout_t layout;
911 init_ni_caldac_layout( &layout );
912 layout.adc_pregain_offset = 8; /* possibly wrong */
913 layout.adc_pregain_offset_fine = 0;
914 layout.adc_postgain_offset = 4;
917 return cal_ni_generic( setup, &layout );
920 static int cal_ni_pci_6024e(calibration_setup_t *setup)
922 ni_caldac_layout_t layout;
924 init_ni_caldac_layout( &layout );
925 layout.adc_pregain_offset = 0;
926 layout.adc_postgain_offset = 4;
927 layout.adc_pregain_offset_fine = 8;
929 layout.dac_offset[ 0 ] = 6;
930 layout.dac_gain[ 0 ] = 11;
931 layout.dac_linearity[ 0 ] = 10;
932 layout.dac_offset[ 1 ] = 9;
933 layout.dac_gain[ 1 ] = 5;
934 layout.dac_linearity[ 1 ] = 1;
936 return cal_ni_generic( setup, &layout );
939 static int cal_ni_pci_6025e(calibration_setup_t *setup)
941 ni_caldac_layout_t layout;
943 init_ni_caldac_layout( &layout );
944 layout.adc_pregain_offset = 0;
945 layout.adc_postgain_offset = 4;
946 layout.adc_pregain_offset_fine = 8;
948 layout.dac_offset[ 0 ] = 6;
949 layout.dac_gain[ 0 ] = 11;
950 layout.dac_linearity[ 0 ] = 10;
951 layout.dac_offset[ 1 ] = 9;
952 layout.dac_gain[ 1 ] = 5;
953 layout.dac_linearity[ 1 ] = 1;
955 return cal_ni_generic( setup, &layout );
958 static int cal_ni_pci_6052e(calibration_setup_t *setup)
961 * This board has noisy caldacs
963 * The NI documentation says (true mb88341 addressing):
964 * 0, 8 AI pregain (coarse, fine)
967 * 14, 7 AI unipolar offset
973 * 10, 6 AO1 reference
976 * For us, these map to (ad8804 channels)
978 * 0, 1 AI pregain (coarse, fine)
981 * 7 AI unipolar offset
990 * or, with mb88341 channels
1000 ni_caldac_layout_t layout;
1002 init_ni_caldac_layout( &layout );
1003 layout.adc_pregain_offset = 0;
1004 layout.adc_postgain_offset = 2;
1005 layout.adc_gain = 4;
1006 layout.adc_unip_offset = 6;
1007 layout.adc_unip_offset_fine = 7;
1008 layout.adc_pregain_offset_fine = 1;
1009 layout.adc_postgain_offset_fine = 3;
1010 layout.adc_gain_fine = 5;
1012 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1013 "for this calibration to work properly\n" );
1014 /* this works when the first two caldacs are ad8804_debug */
1015 layout.dac_offset[ 0 ] = 16 + 3;
1016 layout.dac_gain[ 0 ] = 16 + 1;
1017 layout.dac_gain_fine[ 0 ] = 16 + 2;
1018 layout.dac_linearity[ 0 ] = 16 + 0;
1019 layout.dac_offset[ 1 ] = 16 + 7;
1020 layout.dac_gain[ 1 ] = 16 + 5;
1021 layout.dac_gain_fine[ 1 ] = 16 + 6;
1022 layout.dac_linearity[ 1 ] = 16 + 4;
1024 return cal_ni_generic( setup, &layout );
1027 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
1029 ni_caldac_layout_t layout;
1031 init_ni_caldac_layout( &layout );
1032 layout.adc_pregain_offset = 0;
1033 layout.adc_postgain_offset = 1;
1034 layout.adc_gain = 3;
1035 layout.adc_unip_offset = 2;
1037 return cal_ni_generic( setup, &layout );
1040 static int adc_offset_611x( unsigned int channel )
1042 return 2 * channel + 2;
1044 static int adc_gain_611x( unsigned int channel )
1046 return 2 * channel + 1;
1048 static int dac_offset_611x( unsigned int channel )
1050 return 12 + 2 + 2 * channel;
1052 static int dac_gain_611x( unsigned int channel )
1054 return 12 + 1 + 2 * channel;
1056 static int cal_ni_pci_611x( calibration_setup_t *setup )
1058 generic_layout_t layout;
1060 init_generic_layout( &layout );
1061 layout.adc_offset = adc_offset_611x;
1062 layout.adc_gain = adc_gain_611x;
1063 layout.dac_offset = dac_offset_611x;
1064 layout.dac_gain = dac_gain_611x;
1065 layout.adc_high_observable = ni_reference_611x;
1066 layout.adc_ground_observable = ni_zero_offset_611x;
1067 layout.dac_high_observable = ni_ao_reference_611x;
1068 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1070 return generic_cal_by_channel_and_range( setup, &layout );
1073 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1075 ni_caldac_layout_t layout;
1077 init_ni_caldac_layout( &layout );
1078 layout.adc_pregain_offset = 8;
1079 layout.adc_postgain_offset = 4;
1080 layout.adc_gain = 2;
1081 layout.adc_unip_offset = 7;
1082 layout.dac_offset[ 0 ] = 6;
1083 layout.dac_gain[ 0 ] = 11;
1084 layout.dac_linearity[ 0 ] = 10;
1085 layout.dac_offset[ 1 ] = 9;
1086 layout.dac_gain[ 1 ] = 5;
1087 layout.dac_linearity[ 1 ] = 1;
1089 return cal_ni_generic( setup, &layout );
1092 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1094 ni_caldac_layout_t layout;
1096 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1098 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1099 "for this calibration to work properly\n" );
1101 init_ni_caldac_layout( &layout );
1102 layout.adc_pregain_offset = 8;
1103 layout.adc_postgain_offset = 4;
1104 layout.adc_gain = 2;
1105 layout.adc_unip_offset = 7;
1106 layout.dac_offset[ 0 ] = 6;
1107 layout.dac_gain[ 0 ] = 11;
1108 layout.dac_linearity[ 0 ] = 10;
1109 layout.dac_offset[ 1 ] = 9;
1110 layout.dac_gain[ 1 ] = 5;
1111 layout.dac_linearity[ 1 ] = 1;
1113 return cal_ni_generic( setup, &layout );
1116 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1118 ni_caldac_layout_t layout;
1120 init_ni_caldac_layout( &layout );
1122 layout.adc_pregain_offset = 0;
1123 layout.adc_postgain_offset = 4;
1124 layout.adc_gain = 2;
1125 //layout.adc_unip_offset = 7;
1126 layout.dac_offset[ 0 ] = 6;
1127 layout.dac_gain[ 0 ] = 3;
1128 //layout.dac_linearity[ 0 ] = 10;
1129 layout.dac_offset[ 1 ] = 1;
1130 layout.dac_gain[ 1 ] = 5;
1131 //layout.dac_linearity[ 1 ] = 1;
1133 return cal_ni_generic( setup, &layout );
1136 static int cal_ni_daqcard_6036e( calibration_setup_t *setup )
1138 ni_caldac_layout_t layout;
1140 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 68 ) )
1142 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1143 "for this calibration to work properly\n" );
1146 init_ni_caldac_layout( &layout );
1148 layout.adc_pregain_offset = 0;
1149 layout.adc_pregain_offset_fine = 8;
1150 layout.adc_postgain_offset = 4;
1151 layout.adc_gain = 2;
1153 layout.dac_offset[0] = 6;
1154 layout.dac_gain[0] = 7;
1155 layout.dac_gain_fine[ 0 ] = 11;
1156 layout.dac_linearity[0] = 10;
1158 layout.dac_offset[ 1 ] = 9;
1159 layout.dac_gain[ 1 ] = 3;
1160 layout.dac_gain_fine[ 1 ] = 5;
1161 layout.dac_linearity[1] = 1;
1163 return cal_ni_generic( setup, &layout );
1166 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1167 const ni_caldac_layout_t *layout, unsigned int range )
1171 if( setup->old_calibration == NULL )
1173 reset_caldac( setup, layout->adc_pregain_offset );
1174 reset_caldac( setup, layout->adc_postgain_offset );
1175 reset_caldac( setup, layout->adc_gain );
1176 reset_caldac( setup, layout->adc_pregain_offset_fine );
1177 reset_caldac( setup, layout->adc_postgain_offset_fine );
1178 reset_caldac( setup, layout->adc_gain_fine );
1179 reset_caldac( setup, layout->adc_unip_offset );
1180 reset_caldac( setup, layout->adc_unip_offset_fine );
1183 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1184 0, range, AREF_GROUND, setup->old_calibration );
1187 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1188 reset_caldac( setup, layout->adc_pregain_offset );
1189 reset_caldac( setup, layout->adc_postgain_offset );
1190 reset_caldac( setup, layout->adc_gain );
1191 reset_caldac( setup, layout->adc_pregain_offset_fine );
1192 reset_caldac( setup, layout->adc_postgain_offset_fine );
1193 reset_caldac( setup, layout->adc_gain_fine );
1194 reset_caldac( setup, layout->adc_unip_offset );
1195 reset_caldac( setup, layout->adc_unip_offset_fine );
1200 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1201 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1205 if( setup->da_subdev < 0 ) return;
1207 if( setup->old_calibration == NULL )
1209 reset_caldac( setup, layout->dac_offset[ channel ] );
1210 reset_caldac( setup, layout->dac_gain[ channel ] );
1211 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1212 reset_caldac( setup, layout->dac_linearity[ channel ] );
1215 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1216 channel, range, AREF_GROUND, setup->old_calibration );
1219 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1220 reset_caldac( setup, layout->dac_offset[ channel ] );
1221 reset_caldac( setup, layout->dac_gain[ channel ] );
1222 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1223 reset_caldac( setup, layout->dac_linearity[ channel ] );
1228 static void prep_adc_for_dac( calibration_setup_t *setup, int observable )
1230 unsigned int adc_range;
1233 if( observable < 0 ) return;
1235 chanspec = setup->observables[ observable ].observe_insn.chanspec;
1236 adc_range = CR_RANGE( chanspec );
1238 comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1239 0, adc_range, 0, setup->new_calibration );
1242 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1244 comedi_calibration_setting_t *current_cal;
1248 int ai_unipolar_lowgain, ai_bipolar_lowgain;
1250 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
1251 assert( num_ai_ranges > 0 );
1253 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
1254 ai_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev );
1256 prep_adc_caldacs_generic( setup, layout, ai_bipolar_lowgain );
1258 current_cal = sc_alloc_calibration_setting( setup );
1259 current_cal->subdevice = setup->ad_subdev;
1260 reset_caldac( setup, layout->adc_gain_fine );
1261 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1262 ni_reference_low, layout->adc_gain );
1263 reset_caldac( setup, layout->adc_postgain_offset_fine );
1264 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1265 ni_zero_offset_high, layout->adc_postgain_offset );
1266 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1267 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1268 reset_caldac( setup, layout->adc_pregain_offset_fine );
1269 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1270 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1271 ni_reference_low, layout->adc_gain_fine );
1272 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1273 layout->adc_pregain_offset_fine );
1274 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1275 sc_push_aref( current_cal, SC_ALL_AREFS );
1276 if( layout->adc_unip_offset >= 0 )
1278 sc_push_range( current_cal, SC_ALL_RANGES );
1281 for( range = 0; range < num_ai_ranges; range++ )
1283 if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
1284 sc_push_range( current_cal, range );
1288 /* do seperate unipolar calibration if appropriate */
1289 if( ai_unipolar_lowgain >= 0 )
1291 current_cal = sc_alloc_calibration_setting( setup );
1292 current_cal->subdevice = setup->ad_subdev;
1293 if( layout->adc_unip_offset >= 0 )
1295 reset_caldac( setup, layout->adc_unip_offset_fine );
1296 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1297 layout->adc_unip_offset );
1298 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1299 layout->adc_unip_offset_fine );
1300 /* if we don't have a unipolar offset caldac, do a fully
1301 * independent calibration for unipolar ranges */
1304 prep_adc_caldacs_generic( setup, layout, ai_unipolar_lowgain );
1305 generic_peg( setup, ni_unip_zero_offset_low,
1306 layout->adc_pregain_offset, 1 );
1307 generic_peg( setup, ni_unip_zero_offset_low,
1308 layout->adc_postgain_offset, 1 );
1309 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1310 ni_unip_reference_low, layout->adc_gain );
1311 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1312 ni_unip_zero_offset_high, layout->adc_postgain_offset );
1313 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1314 ni_unip_zero_offset_high, layout->adc_postgain_offset_fine );
1315 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1316 layout->adc_pregain_offset );
1317 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1318 ni_unip_reference_low, layout->adc_gain_fine );
1319 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1320 layout->adc_pregain_offset_fine );
1322 for( range = 0; range < num_ai_ranges; range++ )
1324 if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
1325 sc_push_range( current_cal, range );
1327 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1328 sc_push_aref( current_cal, SC_ALL_AREFS );
1330 if( setup->da_subdev >= 0 && setup->do_output )
1332 unsigned int channel, range;
1333 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1334 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1337 for( channel = 0; channel < 2; channel++ )
1339 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1340 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1341 prep_adc_for_dac( setup, ni_ao_reference( channel ) );
1343 current_cal = sc_alloc_calibration_setting( setup );
1344 current_cal->subdevice = setup->da_subdev;
1345 generic_do_linearity( setup, current_cal, ni_ao_zero_offset( channel ),
1346 ni_ao_mid_linearity( channel ), ni_ao_reference( channel ),
1347 layout->dac_linearity[ channel ] );
1348 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1349 layout->dac_offset[ channel ] );
1350 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1351 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1352 layout->dac_gain[ channel ] );
1353 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1354 layout->dac_gain_fine[ channel ] );
1355 sc_push_channel( current_cal, channel );
1356 for( range = 0; range < num_ao_ranges; range++ )
1358 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1359 sc_push_range( current_cal, range );
1361 sc_push_aref( current_cal, SC_ALL_AREFS );
1363 if( ao_unipolar_lowgain >= 0 )
1365 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1367 current_cal = sc_alloc_calibration_setting( setup );
1368 current_cal->subdevice = setup->da_subdev;
1369 generic_do_linearity( setup, current_cal, ni_ao_unip_low_linearity( channel ),
1370 ni_ao_unip_mid_linearity( channel ), ni_ao_unip_reference( channel ),
1371 layout->dac_linearity[ channel ] );
1372 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1373 layout->dac_offset[ channel ] );
1374 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1375 layout->dac_gain[ channel ] );
1376 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1377 layout->dac_gain_fine[ channel ] );
1378 sc_push_channel( current_cal, channel );
1379 for( range = 0; range < num_ao_ranges; range++ )
1381 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1382 sc_push_range( current_cal, range );
1384 sc_push_aref( current_cal, SC_ALL_AREFS );
1389 retval = write_calibration_file( setup );
1394 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1400 lsb=read_eeprom( setup, lsb_loc );
1401 msb=read_eeprom( setup, msb_loc );
1402 assert( lsb >=0 && msb >= 0 );
1403 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1405 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1406 ref=5.000+1.0e-6*uv;
1407 DPRINT(0, "resulting reference voltage: %g\n", ref );
1408 if( fabs( ref - 5.0 ) > 0.005 )
1409 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1410 "from 5V. Possible bad eeprom address?\n" );
1416 NI 671x and 673x support
1419 static const int channels_per_ad8804 = 16;
1421 static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel)
1423 int ad8804_gain_channels[4] = {8, 2, 11, 5};
1424 int caldac_channel = ad8804_gain_channels[ao_channel % 4];
1425 int caldac_index = ao_channel / 4;
1426 /* just guessing that second ad8804 is works for ao channels 4-7
1427 * the same as the first ad8804 works for ao channels 0-3 */
1428 return caldac_index * channels_per_ad8804 + caldac_channel;
1430 static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel)
1432 int ad8804_linearity_channels[4] = {4, 10, 1, 0};
1433 int caldac_channel = ad8804_linearity_channels[ao_channel % 4];
1434 int caldac_index = ao_channel / 4;
1436 return caldac_index * channels_per_ad8804 + caldac_channel;
1438 static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel)
1440 int ad8804_offset_channels[4] = {7, 6, 9, 3};
1441 int caldac_channel = ad8804_offset_channels[ao_channel % 4];
1442 int caldac_index = ao_channel / 4;
1444 return caldac_index * channels_per_ad8804 + caldac_channel;
1447 static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup,
1448 unsigned int channel, unsigned int ao_range )
1450 return 3 * channel + 0;
1453 static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup,
1454 unsigned int channel, unsigned int ao_range )
1456 return 3 * channel + 1;
1459 static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup,
1460 unsigned int channel, unsigned int ao_range )
1462 return 3 * channel + 2;
1465 static const double ni67xx_unitless_adc_offset = 0.5;
1467 /* determine conversion factor between actual voltage and
1468 * interval [0,1) returned by reads from the calibration adc
1471 static double ni67xx_unitless_adc_slope(calibration_setup_t *setup)
1473 double reference_in_volts;
1474 double reference_unitless;
1478 comedi_range *range;
1479 static const int maxdata = 0x10000;
1482 if(ni_board(setup)->ref_eeprom_lsb >= 0 &&
1483 ni_board(setup)->ref_eeprom_msb >= 0)
1485 reference_in_volts = ni_get_reference(setup,
1486 ni_board(setup)->ref_eeprom_lsb, ni_board(setup)->ref_eeprom_msb );
1489 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
1490 "correction. This might be fixable if you send us an eeprom dump\n"
1491 "(see the demo/eeprom_dump program).\n");
1492 reference_in_volts = 5.0;
1495 memset(&insn, 0, sizeof(insn));
1496 insn.insn = INSN_READ;
1498 insn.subdev = setup->ad_subdev;
1500 insn.chanspec = CR_PACK(0, 0, AREF_GROUND) | CR_ALT_SOURCE;
1501 retval = comedi_do_insn(setup->dev, &insn);
1502 assert(retval >= 0);
1504 range = comedi_get_range(setup->dev, setup->ad_subdev, 0, 0);
1506 reference_unitless = comedi_to_phys(data, range, maxdata);
1508 slope = (reference_unitless - ni67xx_unitless_adc_offset) / reference_in_volts;
1513 /* calibration adc uses RANGE_UNKNOWN, so it will return a value from
1514 0.0 to 1.0 instead of a voltage, so we need to renormalize. */
1515 static void ni67xx_set_target( calibration_setup_t *setup, int obs, double target, double slope)
1517 set_target(setup, obs, target);
1518 /* convert target from volts to interval [0,1) which calibration
1520 setup->observables[obs].target *= slope;
1521 setup->observables[obs].target += ni67xx_unitless_adc_offset;
1524 static void ni67xx_setup_observables( calibration_setup_t *setup )
1526 comedi_insn tmpl, po_tmpl;
1528 int num_ao_channels;
1532 slope = ni67xx_unitless_adc_slope(setup);
1534 /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */
1535 setup->sv_order = 1;
1537 num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev);
1538 assert(num_ao_channels >= 0);
1540 memset( &tmpl, 0, sizeof(tmpl) );
1541 tmpl.insn = INSN_READ;
1543 tmpl.subdev = setup->ad_subdev;
1545 memset( &po_tmpl, 0, sizeof(po_tmpl) );
1546 po_tmpl.insn = INSN_WRITE;
1548 po_tmpl.subdev = setup->da_subdev;
1550 setup->n_observables = 0;
1552 for(i = 0; i < num_ao_channels; i++)
1554 o = setup->observables + ni67xx_ao_ground_observable_index( setup,
1556 o->reference_source = -1;
1557 assert( o->name == NULL );
1558 asprintf(&o->name, "dac%i ground, ground referenced", i);
1559 o->preobserve_insn = po_tmpl;
1560 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1561 o->preobserve_insn.data = o->preobserve_data;
1562 o->observe_insn = tmpl;
1563 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1564 ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0, slope);
1565 setup->n_observables++;
1567 o = setup->observables + ni67xx_ao_mid_observable_index( setup,
1569 o->reference_source = -1;
1570 assert( o->name == NULL );
1571 asprintf(&o->name, "dac%i mid, ground referenced", i);
1572 o->preobserve_insn = po_tmpl;
1573 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1574 o->preobserve_insn.data = o->preobserve_data;
1575 o->observe_insn = tmpl;
1576 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1577 ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0, slope);
1578 setup->n_observables++;
1580 o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0);
1581 o->reference_source = -1;
1582 assert( o->name == NULL );
1583 asprintf(&o->name, "dac%i high, ground referenced", i);
1584 o->preobserve_insn = po_tmpl;
1585 o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND );
1586 o->preobserve_insn.data = o->preobserve_data;
1587 o->observe_insn = tmpl;
1588 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1589 ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0, slope);
1590 setup->n_observables++;
1596 static int cal_ni_pci_6711(calibration_setup_t *setup)
1598 generic_layout_t layout;
1600 init_generic_layout( &layout );
1601 layout.dac_gain = ni67xx_ao_gain_caldac;
1602 layout.dac_linearity = ni67xx_ao_linearity_caldac;
1603 layout.dac_offset = ni67xx_ao_offset_caldac;
1604 layout.dac_high_observable = ni67xx_ao_high_observable_index;
1605 layout.dac_mid_observable = ni67xx_ao_mid_observable_index;
1606 layout.dac_ground_observable = ni67xx_ao_ground_observable_index;
1607 layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 );
1608 return generic_cal_ao(setup, &layout);