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_6014(calibration_setup_t *setup);
57 static int cal_ni_pci_6024e(calibration_setup_t *setup);
58 static int cal_ni_pci_6025e(calibration_setup_t *setup);
59 static int cal_ni_pci_6032e(calibration_setup_t *setup);
60 static int cal_ni_pci_6034e(calibration_setup_t *setup);
61 static int cal_ni_pci_6035e(calibration_setup_t *setup);
62 static int cal_ni_pci_6036e(calibration_setup_t *setup);
63 static int cal_ni_pci_6071e(calibration_setup_t *setup);
64 static int cal_ni_pxi_6071e(calibration_setup_t *setup);
65 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup);
66 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup);
67 static int cal_ni_pci_6023e(calibration_setup_t *setup);
68 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup);
69 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup);
70 static int cal_ni_pci_6052e(calibration_setup_t *setup);
71 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup);
72 static int cal_ni_pci_611x(calibration_setup_t *setup);
73 static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup);
74 static int cal_ni_daqcard_6062e(calibration_setup_t *setup);
75 static int cal_ni_daqcard_6024e(calibration_setup_t *setup);
76 static int cal_ni_daqcard_6036e(calibration_setup_t *setup);
77 static int cal_ni_pci_6711(calibration_setup_t *setup);
79 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
81 static struct board_struct boards[]={
82 { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
83 { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
84 { "at-mio-16e-1", STATUS_DONE, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
85 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
86 { "at-mio-16e-10", STATUS_DONE, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
87 { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
88 { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
89 { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
90 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
91 { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
92 { "DAQCard-6036E", STATUS_DONE, cal_ni_daqcard_6036e, ni_setup_observables, 0x1ab, 0x1ac },
93 { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
94 { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
95 { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
96 { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
97 { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
98 { "pci-6014", STATUS_SOME, cal_ni_pci_6014, ni_setup_observables, 0x1ab, 0x1ac },
99 { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
100 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
101 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
102 { "pci-6031e", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
103 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
104 { "pci-6033e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1b7, 0x1b8 },
105 { "pci-6034e", STATUS_SOME, cal_ni_pci_6034e, ni_setup_observables, 0x1bb, 0x1bc },
106 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
107 { "pci-6036e", STATUS_DONE, cal_ni_pci_6036e, ni_setup_observables, 0x1ab, 0x1ac },
108 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
109 { "pci-6071e", STATUS_DONE, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
110 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
111 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
112 { "pxi-6025e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
113 { "pxi-6030e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
114 { "pxi-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
115 { "pxi-6040e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
116 { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
117 { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
118 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
119 { "pci-6711", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
120 { "pci-6713", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
121 { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
122 { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
123 { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
124 { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
125 { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
126 { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
128 { "at-mio-64e-3", cal_ni_16e_1 },
131 #define n_boards (sizeof(boards)/sizeof(boards[0]))
133 static const int ni_num_observables = 20;
135 ni_zero_offset_low = 0,
138 ni_unip_zero_offset_low,
139 ni_unip_zero_offset_high,
140 ni_unip_reference_low,
147 ni_ao0_unip_zero_offset,
148 ni_ao0_unip_reference,
149 ni_ao0_unip_low_linearity,
150 ni_ao0_unip_mid_linearity,
151 ni_ao1_unip_zero_offset,
152 ni_ao1_unip_reference,
153 ni_ao1_unip_low_linearity,
154 ni_ao1_unip_mid_linearity,
156 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
158 if( channel ) return ni_ao1_zero_offset;
159 else return ni_ao0_zero_offset;
161 static inline unsigned int ni_ao_reference( unsigned int channel )
163 if( channel ) return ni_ao1_reference;
164 else return ni_ao0_reference;
166 static inline unsigned int ni_ao_mid_linearity( unsigned int channel )
168 if( channel ) return ni_ao1_linearity;
169 else return ni_ao0_linearity;
171 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
173 if( channel ) return ni_ao1_unip_zero_offset;
174 else return ni_ao0_unip_zero_offset;
176 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
178 if( channel ) return ni_ao1_unip_reference;
179 else return ni_ao0_unip_reference;
181 static inline unsigned int ni_ao_unip_low_linearity( unsigned int channel )
183 if( channel ) return ni_ao1_unip_low_linearity;
184 else return ni_ao0_unip_low_linearity;
186 static inline unsigned int ni_ao_unip_mid_linearity( unsigned int channel )
188 if( channel ) return ni_ao1_unip_mid_linearity;
189 else return ni_ao0_unip_mid_linearity;
192 static const int num_ao_observables_611x = 4;
193 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
194 unsigned int channel, unsigned int range ) {
195 assert( range == 0 );
198 static int ni_ao_reference_611x( const calibration_setup_t *setup,
199 unsigned int channel, unsigned int range ) {
200 assert( range == 0 );
201 return 2 * channel + 1;
203 static int ni_zero_offset_611x( const calibration_setup_t *setup,
204 unsigned int channel, unsigned int range ) {
205 return num_ao_observables_611x + 8 * range + 2 * channel;
207 static int ni_reference_611x( const calibration_setup_t *setup,
208 unsigned int channel, unsigned int range ) {
209 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
212 enum reference_sources {
217 REF_CALSRC_CALSRC = 4,
222 static inline unsigned int REF_DAC_GND( unsigned int channel )
224 if( channel ) return REF_DAC1_GND;
225 else return REF_DAC0_GND;
227 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
229 if( channel ) return REF_DAC1_CALSRC;
230 else return REF_DAC0_CALSRC;
233 static struct board_struct* ni_board( calibration_setup_t *setup )
235 return setup->private_data;
240 int adc_pregain_offset;
241 int adc_postgain_offset;
243 int adc_pregain_offset_fine;
244 int adc_postgain_offset_fine;
247 int adc_unip_offset_fine;
249 int dac_offset_fine[ 2 ];
251 int dac_gain_fine[ 2 ];
252 int dac_linearity[ 2 ];
253 } ni_caldac_layout_t;
255 static int cal_ni_generic( calibration_setup_t *setup,
256 const ni_caldac_layout_t *layout );
258 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
262 layout->adc_pregain_offset = -1;
263 layout->adc_postgain_offset = -1;
264 layout->adc_gain = -1;
265 layout->adc_unip_offset = -1;
266 layout->adc_unip_offset_fine = -1;
267 layout->adc_pregain_offset_fine = -1;
268 layout->adc_postgain_offset_fine = -1;
269 layout->adc_gain_fine = -1;
270 for( i = 0; i < 2; i++ )
272 layout->dac_offset[ i ] = -1;
273 layout->dac_offset_fine[ i ] = -1;
274 layout->dac_gain[ i ] = -1;
275 layout->dac_gain_fine[ i ] = -1;
276 layout->dac_linearity[ i ] = -1;
280 int ni_setup( calibration_setup_t *setup , const char *device_name )
284 retval = ni_setup_board( setup, device_name );
285 if( retval < 0 ) return retval;
286 setup_caldacs( setup, setup->caldac_subdev );
291 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
295 for(i = 0; i < n_boards; i++ ){
296 if(!strcmp( device_name, boards[i].name )){
297 setup->status = boards[i].status;
298 setup->do_cal = boards[i].cal;
299 setup->private_data = &boards[ i ];
300 boards[i].setup_observables( setup );
304 if( i == n_boards ) return -1;
308 static void ni_setup_ao_observables( calibration_setup_t *setup )
311 comedi_insn tmpl, po_tmpl;
312 unsigned int channel;
313 int ai_bipolar_lowgain;
314 int ao_bipolar_lowgain;
315 int ao_unipolar_lowgain;
317 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
318 assert(ai_bipolar_lowgain >= 0);
319 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
320 assert(ao_bipolar_lowgain >= 0);
321 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
323 memset(&tmpl,0,sizeof(tmpl));
324 tmpl.insn = INSN_READ;
326 tmpl.subdev = setup->ad_subdev;
328 memset(&po_tmpl, 0, sizeof(po_tmpl));
329 po_tmpl.insn = INSN_WRITE;
331 po_tmpl.subdev = setup->da_subdev;
333 for( channel = 0; channel < 2; channel++ )
336 o = setup->observables + ni_ao_zero_offset( channel );
337 assert( o->name == NULL );
338 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
339 o->preobserve_insn = po_tmpl;
340 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
341 o->preobserve_insn.data = o->preobserve_data;
342 o->observe_insn = tmpl;
343 o->observe_insn.chanspec =
344 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
345 | CR_ALT_SOURCE | CR_ALT_FILTER;
346 o->reference_source = REF_DAC_GND( channel );
347 set_target( setup, ni_ao_zero_offset( channel ),0.0);
350 o = setup->observables + ni_ao_reference( channel );
351 assert( o->name == NULL );
352 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
353 o->preobserve_insn = po_tmpl;
354 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
355 o->preobserve_insn.data = o->preobserve_data;
356 o->observe_insn = tmpl;
357 o->observe_insn.chanspec =
358 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
359 | CR_ALT_SOURCE | CR_ALT_FILTER;
360 o->reference_source = REF_DAC_GND( channel );
361 set_target( setup, ni_ao_reference( channel ),8.0);
363 /* ao linearity, mid */
364 o = setup->observables + ni_ao_mid_linearity( channel );
365 assert( o->name == NULL );
366 asprintf( &o->name, "ao %i, linearity (mid), low gain", channel );
367 o->preobserve_insn = po_tmpl;
368 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
369 o->preobserve_insn.data = o->preobserve_data;
370 o->observe_insn = tmpl;
371 o->observe_insn.chanspec =
372 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
373 | CR_ALT_SOURCE | CR_ALT_FILTER;
374 o->reference_source = REF_DAC_GND( channel );
375 set_target( setup, ni_ao_mid_linearity( channel ),4.0);
377 if( ao_unipolar_lowgain >= 0 )
379 /* ao unipolar zero offset */
380 o = setup->observables + ni_ao_unip_zero_offset( channel );
381 assert( o->name == NULL );
382 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
383 o->preobserve_insn = po_tmpl;
384 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
385 o->preobserve_insn.data = o->preobserve_data;
386 o->observe_insn = tmpl;
387 o->observe_insn.chanspec =
388 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
389 | CR_ALT_SOURCE | CR_ALT_FILTER;
390 o->reference_source = REF_DAC_GND( channel );
391 set_target( setup, ni_ao_unip_zero_offset( channel ),0.0);
393 /* ao unipolar gain */
394 o = setup->observables + ni_ao_unip_reference( channel );
395 assert( o->name == NULL );
396 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
397 o->preobserve_insn = po_tmpl;
398 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
399 o->preobserve_insn.data = o->preobserve_data;
400 o->observe_insn = tmpl;
401 o->observe_insn.chanspec =
402 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
403 | CR_ALT_SOURCE | CR_ALT_FILTER;
404 o->reference_source = REF_DAC_GND( channel );
405 set_target( setup, ni_ao_unip_reference( channel ), 9.0);
407 /* ao unipolar linearity, mid */
408 o = setup->observables + ni_ao_unip_mid_linearity( channel );
409 assert( o->name == NULL );
410 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
411 o->preobserve_insn = po_tmpl;
412 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
413 o->preobserve_insn.data = o->preobserve_data;
414 o->observe_insn = tmpl;
415 o->observe_insn.chanspec =
416 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
417 | CR_ALT_SOURCE | CR_ALT_FILTER;
418 o->reference_source = REF_DAC_GND( channel );
419 set_target( setup, ni_ao_unip_mid_linearity( channel ), 5.0);
421 /* ao unipolar linearity, low */
422 o = setup->observables + ni_ao_unip_low_linearity( channel );
423 assert( o->name == NULL );
424 asprintf( &o->name, "ao %i, unipolar linearity (low), low gain", channel );
425 o->preobserve_insn = po_tmpl;
426 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
427 o->preobserve_insn.data = o->preobserve_data;
428 o->observe_insn = tmpl;
429 o->observe_insn.chanspec =
430 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
431 | CR_ALT_SOURCE | CR_ALT_FILTER;
432 o->reference_source = REF_DAC_GND( channel );
433 set_target( setup, ni_ao_unip_low_linearity( channel ), 1.0);
438 static void ni_setup_observables( calibration_setup_t *setup )
442 int bipolar_highgain;
443 int unipolar_lowgain;
444 int unipolar_highgain;
445 double voltage_reference;
448 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
449 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
450 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
451 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
453 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
454 ni_board( setup )->ref_eeprom_msb >= 0 )
456 voltage_reference = ni_get_reference( setup,
457 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
460 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
461 "correction. This might be fixable if you send us an eeprom dump\n"
462 "(see the demo/eeprom_dump program).\n");
463 voltage_reference = 5.0;
466 memset(&tmpl,0,sizeof(tmpl));
467 tmpl.insn = INSN_READ;
469 tmpl.subdev = setup->ad_subdev;
471 setup->n_observables = ni_num_observables;
473 /* 0 offset, low gain */
474 o = setup->observables + ni_zero_offset_low;
475 o->name = "ai, bipolar zero offset, low gain";
476 o->observe_insn = tmpl;
477 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
478 | CR_ALT_SOURCE | CR_ALT_FILTER;
479 o->reference_source = REF_GND_GND;
482 /* 0 offset, high gain */
483 o = setup->observables + ni_zero_offset_high;
484 o->name = "ai, bipolar zero offset, high gain";
485 o->observe_insn = tmpl;
486 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
487 | CR_ALT_SOURCE | CR_ALT_FILTER;
488 o->reference_source = REF_GND_GND;
491 /* voltage reference */
492 o = setup->observables + ni_reference_low;
493 o->name = "ai, bipolar voltage reference, low gain";
494 o->observe_insn = tmpl;
495 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
496 | CR_ALT_SOURCE | CR_ALT_FILTER;
497 o->reference_source = REF_CALSRC_GND;
498 o->target = voltage_reference;
500 if(unipolar_lowgain>=0){
501 o = setup->observables + ni_unip_zero_offset_low;
502 o->name = "ai, unipolar zero offset, low gain";
503 o->observe_insn = tmpl;
504 o->observe_insn.chanspec =
505 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
506 | CR_ALT_SOURCE | CR_ALT_FILTER;
507 o->reference_source = REF_GND_GND;
508 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
510 o = setup->observables + ni_unip_reference_low;
511 o->name = "ai, unipolar voltage reference, low gain";
512 o->observe_insn = tmpl;
513 o->observe_insn.chanspec =
514 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
515 | CR_ALT_SOURCE | CR_ALT_FILTER;
516 o->reference_source = REF_CALSRC_GND;
517 o->target = voltage_reference;
520 if(unipolar_highgain >= 0)
522 o = setup->observables + ni_unip_zero_offset_high;
523 o->name = "ai, unipolar zero offset, high gain";
524 o->observe_insn = tmpl;
525 o->observe_insn.chanspec =
526 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
527 | CR_ALT_SOURCE | CR_ALT_FILTER;
528 o->reference_source = REF_GND_GND;
529 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
532 if(setup->da_subdev >= 0)
533 ni_setup_ao_observables( setup );
536 /* for +-50V and +-20V ranges, the reference source goes 0V
537 * to 50V instead of 0V to 5V */
538 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
542 bits = 200.0 * ( *voltage / reference );
543 if( bits > 200 ) bits = 200;
544 if( bits < 0 ) bits = 0;
546 *voltage = reference * ( bits / 200.0 );
550 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
552 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
555 static void reference_target_611x( calibration_setup_t *setup,
556 observable *o, double master_reference, unsigned int range )
558 int cal_gain_reg_bits;
561 comedi_range *range_ptr;
563 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
564 assert( range_ptr != NULL );
565 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
566 else reference = master_reference;
567 target = range_ptr->max * 0.8;
569 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
571 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
575 static void ni_setup_observables_611x( calibration_setup_t *setup )
580 double master_reference;
582 int num_ai_channels, num_ai_ranges;
583 static const int num_ao_channels = 2;
585 setup->sv_settling_time_ns = 10000000;
586 setup->sv_order = 14;
588 master_reference = ni_get_reference( setup,
589 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
591 memset(&tmpl,0,sizeof(tmpl));
592 tmpl.insn = INSN_READ;
594 tmpl.subdev = setup->ad_subdev;
596 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
597 assert( num_ai_channels >= 0 );
598 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
599 assert( num_ai_ranges >= 0 );
601 for( channel = 0; channel < num_ai_channels; channel++ )
603 for( range = 0; range < num_ai_ranges; range++ )
606 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
607 assert( o->name == NULL );
608 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
610 o->observe_insn = tmpl;
611 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
612 | CR_ALT_SOURCE | CR_ALT_FILTER;
613 o->reference_source = REF_GND_GND;
616 /* voltage reference */
617 o = setup->observables + ni_reference_611x( setup, channel, range );
618 assert( o->name == NULL );
619 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
621 o->observe_insn = tmpl;
622 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
623 | CR_ALT_SOURCE | CR_ALT_FILTER;
624 reference_target_611x( setup, o, master_reference, range );
628 memset(&po_tmpl,0,sizeof(po_tmpl));
629 po_tmpl.insn = INSN_WRITE;
631 po_tmpl.subdev = setup->da_subdev;
633 for( channel = 0; channel < num_ao_channels; channel ++ )
635 static const int ai_range_for_ao = 2;
638 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
639 assert( o->name == NULL );
640 asprintf( &o->name, "ao ch %i, zero offset", channel );
641 o->preobserve_insn = po_tmpl;
642 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
643 o->preobserve_insn.data = o->preobserve_data;
644 o->observe_insn = tmpl;
645 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
646 | CR_ALT_SOURCE | CR_ALT_FILTER;
647 o->reference_source = REF_DAC_GND( channel );
648 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
651 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
652 assert( o->name == NULL );
653 asprintf( &o->name, "ao ch %i, reference voltage", channel );
654 o->preobserve_insn = po_tmpl;
655 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
656 o->preobserve_insn.data = o->preobserve_data;
657 o->observe_insn = tmpl;
658 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
659 | CR_ALT_SOURCE | CR_ALT_FILTER;
660 o->reference_source = REF_DAC_GND( channel );
661 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
664 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
667 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
669 ni_caldac_layout_t layout;
671 init_ni_caldac_layout( &layout );
672 layout.adc_pregain_offset = 8;
673 layout.adc_postgain_offset = 2;
675 layout.adc_gain_fine = 1;
677 return cal_ni_generic( setup, &layout );
680 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
682 ni_caldac_layout_t layout;
684 init_ni_caldac_layout( &layout );
685 layout.adc_pregain_offset = 8;
686 layout.adc_postgain_offset = 2;
688 layout.adc_gain_fine = 1;
689 layout.dac_offset[ 0 ] = 6;
690 layout.dac_gain[ 0 ] = 4;
691 layout.dac_offset[ 1 ] = 7;
692 layout.dac_gain[ 1 ] = 5;
694 return cal_ni_generic( setup, &layout );
697 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
699 ni_caldac_layout_t layout;
701 init_ni_caldac_layout( &layout );
702 layout.adc_pregain_offset = 8;
703 layout.adc_postgain_offset = 2;
704 layout.adc_postgain_offset_fine = 3;
706 layout.adc_gain_fine = 1;
707 layout.dac_offset[ 0 ] = 6;
708 layout.dac_gain[ 0 ] = 4;
709 layout.dac_offset[ 1 ] = 7;
710 layout.dac_gain[ 1 ] = 5;
712 return cal_ni_generic( setup, &layout );
715 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
717 ni_caldac_layout_t layout;
719 init_ni_caldac_layout( &layout );
720 layout.adc_pregain_offset = 0;
721 layout.adc_postgain_offset = 1;
723 layout.adc_unip_offset = 2;
724 layout.dac_offset[0] = 5;
725 layout.dac_gain[0] = 6;
726 layout.dac_linearity[0] = 4;
727 layout.dac_offset[1] = 8;
728 layout.dac_gain[1] = 9;
729 layout.dac_linearity[1] = 7;
731 return cal_ni_generic( setup, &layout );
734 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
736 return cal_ni_at_mio_16e_1(setup);
739 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
741 ni_caldac_layout_t layout;
743 init_ni_caldac_layout( &layout );
744 layout.adc_pregain_offset = 0;
745 layout.adc_postgain_offset = 1;
746 layout.adc_unip_offset = 2;
748 layout.dac_offset[ 0 ] = 5;
749 layout.dac_gain[ 0 ] = 6;
750 layout.dac_linearity[ 0 ] = 4;
751 layout.dac_offset[ 1 ] = 8;
752 layout.dac_gain[ 1 ] = 9;
753 layout.dac_linearity[ 1 ] = 7;
755 return cal_ni_generic( setup, &layout );
758 static int cal_ni_pci_6014(calibration_setup_t *setup)
760 ni_caldac_layout_t layout;
762 init_ni_caldac_layout( &layout );
763 layout.adc_pregain_offset = 0;
764 layout.adc_postgain_offset = 4;
765 layout.adc_pregain_offset_fine = 8;
767 layout.dac_offset[0] = 6;
768 layout.dac_offset_fine[0] = 10;
769 layout.dac_gain[0] = 7;
770 layout.dac_gain_fine[0] = 11;
771 layout.dac_offset[1] = 9;
772 layout.dac_offset_fine[1] = 1;
773 layout.dac_gain[1] = 3;
774 layout.dac_gain_fine[1] = 5;
775 return cal_ni_generic( setup, &layout );
778 static int cal_ni_pci_6032e(calibration_setup_t *setup)
780 ni_caldac_layout_t layout;
782 init_ni_caldac_layout( &layout );
783 layout.adc_pregain_offset = 8;
784 layout.adc_postgain_offset = 2;
785 layout.adc_postgain_offset_fine = 3;
787 layout.adc_gain_fine = 1;
789 return cal_ni_generic( setup, &layout );
792 static int cal_ni_pci_6034e(calibration_setup_t *setup)
794 ni_caldac_layout_t layout;
796 init_ni_caldac_layout( &layout );
797 layout.adc_pregain_offset = 0;
798 layout.adc_pregain_offset_fine = 8;
799 layout.adc_postgain_offset = 4;
802 return cal_ni_generic( setup, &layout );
805 static int cal_ni_pci_6035e(calibration_setup_t *setup)
807 /* this is for the ad8804_debug caldac */
808 ni_caldac_layout_t layout;
810 init_ni_caldac_layout( &layout );
811 layout.adc_pregain_offset = 0;
812 layout.adc_pregain_offset_fine = 8;
813 layout.adc_postgain_offset = 4;
815 layout.dac_offset[ 0 ] = 6;
816 layout.dac_gain[ 0 ] = 11;
817 layout.dac_linearity[ 0 ] = 10;
818 layout.dac_offset[ 1 ] = 9;
819 layout.dac_gain[ 1 ] = 5;
820 layout.dac_linearity[ 1 ] = 1;
822 return cal_ni_generic( setup, &layout );
825 static int cal_ni_pci_6036e(calibration_setup_t *setup)
827 ni_caldac_layout_t layout;
829 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
831 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
832 "for this calibration to work properly\n" );
835 /* this is for the ad8804_debug caldac */
836 init_ni_caldac_layout( &layout );
837 layout.adc_pregain_offset = 0;
838 layout.adc_postgain_offset = 4;
839 layout.adc_pregain_offset_fine = 8;
841 layout.dac_offset[ 0 ] = 6;
842 layout.dac_gain[ 0 ] = 7;
843 layout.dac_gain_fine[ 0 ] = 11;
844 layout.dac_linearity[ 0 ] = 10;
845 layout.dac_offset[ 1 ] = 9;
846 layout.dac_gain[ 1 ] = 3;
847 layout.dac_gain_fine[ 1 ] = 5;
848 layout.dac_linearity[ 1 ] = 1;
850 return cal_ni_generic( setup, &layout );
853 static int cal_ni_pci_6071e(calibration_setup_t *setup)
855 ni_caldac_layout_t layout;
857 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
859 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
860 "for this calibration to work properly\n" );
863 init_ni_caldac_layout( &layout );
864 layout.adc_pregain_offset = 8;
865 layout.adc_postgain_offset = 4;
866 layout.adc_unip_offset = 7;
868 layout.dac_offset[ 0 ] = 6;
869 layout.dac_gain[ 0 ] = 11;
870 layout.dac_linearity[ 0 ] = 10;
871 layout.dac_offset[ 1 ] = 9;
872 layout.dac_gain[ 1 ] = 5;
873 layout.dac_linearity[ 1 ] = 1;
874 return cal_ni_generic( setup, &layout );
877 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
879 ni_caldac_layout_t layout;
881 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
883 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
884 "for this calibration to work properly\n" );
887 init_ni_caldac_layout( &layout );
888 layout.adc_pregain_offset = 0;
889 layout.adc_pregain_offset_fine = 8;
890 layout.adc_postgain_offset = 4;
892 layout.dac_offset[ 0 ] = 6;
893 layout.dac_gain[ 0 ] = 11;
894 layout.dac_linearity[ 0 ] = 10;
895 layout.dac_offset[ 1 ] = 9;
896 layout.dac_gain[ 1 ] = 5;
897 layout.dac_linearity[ 1 ] = 1;
898 return cal_ni_generic( setup, &layout );
901 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
903 ni_caldac_layout_t layout;
905 if(comedi_get_version_code(setup->dev) <= COMEDI_VERSION_CODE(0, 7, 68))
907 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
908 "for this calibration to work properly\n" );
910 init_ni_caldac_layout( &layout );
911 layout.adc_pregain_offset = 0;
912 layout.adc_pregain_offset_fine = 8;
913 layout.adc_postgain_offset = 4;
915 layout.adc_unip_offset = 7;
916 layout.dac_offset[ 0 ] = 6;
917 layout.dac_gain[ 0 ] = 11;
918 layout.dac_linearity[ 0 ] = 10;
919 layout.dac_offset[ 1 ] = 9;
920 layout.dac_gain[ 1 ] = 5;
921 layout.dac_linearity[1] = 1;
922 return cal_ni_generic( setup, &layout );
925 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
927 ni_caldac_layout_t layout;
929 init_ni_caldac_layout( &layout );
930 layout.adc_pregain_offset = 8;
931 layout.adc_postgain_offset = 2;
933 layout.adc_gain_fine = 1;
934 layout.adc_unip_offset = 7;
935 layout.dac_offset[ 0 ] = 6;
936 layout.dac_gain[ 0 ] = 4;
937 layout.dac_offset[ 1 ] = 7;
938 layout.dac_gain[ 1 ] = 5;
940 return cal_ni_generic( setup, &layout );
943 static int cal_ni_pci_6023e(calibration_setup_t *setup)
945 /* for comedi-0.7.65 */
946 ni_caldac_layout_t layout;
948 init_ni_caldac_layout( &layout );
949 layout.adc_pregain_offset = 8; /* possibly wrong */
950 layout.adc_pregain_offset_fine = 0;
951 layout.adc_postgain_offset = 4;
954 return cal_ni_generic( setup, &layout );
957 static int cal_ni_pci_6024e(calibration_setup_t *setup)
959 ni_caldac_layout_t layout;
961 init_ni_caldac_layout( &layout );
962 layout.adc_pregain_offset = 0;
963 layout.adc_postgain_offset = 4;
964 layout.adc_pregain_offset_fine = 8;
966 layout.dac_offset[ 0 ] = 6;
967 layout.dac_gain[ 0 ] = 11;
968 layout.dac_linearity[ 0 ] = 10;
969 layout.dac_offset[ 1 ] = 9;
970 layout.dac_gain[ 1 ] = 5;
971 layout.dac_linearity[ 1 ] = 1;
973 return cal_ni_generic( setup, &layout );
976 static int cal_ni_pci_6025e(calibration_setup_t *setup)
978 ni_caldac_layout_t layout;
980 init_ni_caldac_layout( &layout );
981 layout.adc_pregain_offset = 0;
982 layout.adc_postgain_offset = 4;
983 layout.adc_pregain_offset_fine = 8;
985 layout.dac_offset[ 0 ] = 6;
986 layout.dac_gain[ 0 ] = 11;
987 layout.dac_linearity[ 0 ] = 10;
988 layout.dac_offset[ 1 ] = 9;
989 layout.dac_gain[ 1 ] = 5;
990 layout.dac_linearity[ 1 ] = 1;
992 return cal_ni_generic( setup, &layout );
995 static int cal_ni_pci_6052e(calibration_setup_t *setup)
998 * This board has noisy caldacs
1000 * The NI documentation says (true mb88341 addressing):
1001 * 0, 8 AI pregain (coarse, fine)
1003 * 2, 10 AI reference
1004 * 14, 7 AI unipolar offset
1007 * 8, 4 AO0 reference
1010 * 10, 6 AO1 reference
1013 * For us, these map to (ad8804 channels)
1015 * 0, 1 AI pregain (coarse, fine)
1018 * 7 AI unipolar offset
1021 * 1, 2 AO0 reference
1024 * 5, 6 AO1 reference
1027 * or, with mb88341 channels
1030 * 7, 3 AO0 reference
1033 * 9, 5 AO1 reference
1037 ni_caldac_layout_t layout;
1039 init_ni_caldac_layout( &layout );
1040 layout.adc_pregain_offset = 0;
1041 layout.adc_postgain_offset = 2;
1042 layout.adc_gain = 4;
1043 layout.adc_unip_offset = 6;
1044 layout.adc_unip_offset_fine = 7;
1045 layout.adc_pregain_offset_fine = 1;
1046 layout.adc_postgain_offset_fine = 3;
1047 layout.adc_gain_fine = 5;
1049 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1050 "for this calibration to work properly\n" );
1051 /* this works when the first two caldacs are ad8804_debug */
1052 layout.dac_offset[ 0 ] = 16 + 3;
1053 layout.dac_gain[ 0 ] = 16 + 1;
1054 layout.dac_gain_fine[ 0 ] = 16 + 2;
1055 layout.dac_linearity[ 0 ] = 16 + 0;
1056 layout.dac_offset[ 1 ] = 16 + 7;
1057 layout.dac_gain[ 1 ] = 16 + 5;
1058 layout.dac_gain_fine[ 1 ] = 16 + 6;
1059 layout.dac_linearity[ 1 ] = 16 + 4;
1061 return cal_ni_generic( setup, &layout );
1064 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
1066 ni_caldac_layout_t layout;
1068 init_ni_caldac_layout( &layout );
1069 layout.adc_pregain_offset = 0;
1070 layout.adc_postgain_offset = 1;
1071 layout.adc_gain = 3;
1072 layout.adc_unip_offset = 2;
1074 return cal_ni_generic( setup, &layout );
1077 static int adc_offset_611x( unsigned int channel )
1079 return 2 * channel + 2;
1081 static int adc_gain_611x( unsigned int channel )
1083 return 2 * channel + 1;
1085 static int dac_offset_611x( unsigned int channel )
1087 return 12 + 2 + 2 * channel;
1089 static int dac_gain_611x( unsigned int channel )
1091 return 12 + 1 + 2 * channel;
1093 static int cal_ni_pci_611x( calibration_setup_t *setup )
1095 generic_layout_t layout;
1097 init_generic_layout( &layout );
1098 layout.adc_offset = adc_offset_611x;
1099 layout.adc_gain = adc_gain_611x;
1100 layout.dac_offset = dac_offset_611x;
1101 layout.dac_gain = dac_gain_611x;
1102 layout.adc_high_observable = ni_reference_611x;
1103 layout.adc_ground_observable = ni_zero_offset_611x;
1104 layout.dac_high_observable = ni_ao_reference_611x;
1105 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1107 return generic_cal_by_channel_and_range( setup, &layout );
1110 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1112 ni_caldac_layout_t layout;
1114 init_ni_caldac_layout( &layout );
1115 layout.adc_pregain_offset = 8;
1116 layout.adc_postgain_offset = 4;
1117 layout.adc_gain = 2;
1118 layout.adc_unip_offset = 7;
1119 layout.dac_offset[ 0 ] = 6;
1120 layout.dac_gain[ 0 ] = 11;
1121 layout.dac_linearity[ 0 ] = 10;
1122 layout.dac_offset[ 1 ] = 9;
1123 layout.dac_gain[ 1 ] = 5;
1124 layout.dac_linearity[ 1 ] = 1;
1126 return cal_ni_generic( setup, &layout );
1129 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1131 ni_caldac_layout_t layout;
1133 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1135 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1136 "for this calibration to work properly\n" );
1138 init_ni_caldac_layout( &layout );
1139 layout.adc_pregain_offset = 8;
1140 layout.adc_postgain_offset = 4;
1141 layout.adc_gain = 2;
1142 layout.adc_unip_offset = 7;
1143 layout.dac_offset[ 0 ] = 6;
1144 layout.dac_gain[ 0 ] = 11;
1145 layout.dac_linearity[ 0 ] = 10;
1146 layout.dac_offset[ 1 ] = 9;
1147 layout.dac_gain[ 1 ] = 5;
1148 layout.dac_linearity[ 1 ] = 1;
1150 return cal_ni_generic( setup, &layout );
1153 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1155 ni_caldac_layout_t layout;
1157 init_ni_caldac_layout( &layout );
1159 layout.adc_pregain_offset = 0;
1160 layout.adc_postgain_offset = 4;
1161 layout.adc_gain = 2;
1162 //layout.adc_unip_offset = 7;
1163 layout.dac_offset[ 0 ] = 6;
1164 layout.dac_gain[ 0 ] = 3;
1165 //layout.dac_linearity[ 0 ] = 10;
1166 layout.dac_offset[ 1 ] = 1;
1167 layout.dac_gain[ 1 ] = 5;
1168 //layout.dac_linearity[ 1 ] = 1;
1170 return cal_ni_generic( setup, &layout );
1173 static int cal_ni_daqcard_6036e( calibration_setup_t *setup )
1175 ni_caldac_layout_t layout;
1177 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 68 ) )
1179 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1180 "for this calibration to work properly\n" );
1183 init_ni_caldac_layout( &layout );
1185 layout.adc_pregain_offset = 0;
1186 layout.adc_pregain_offset_fine = 8;
1187 layout.adc_postgain_offset = 4;
1188 layout.adc_gain = 2;
1190 layout.dac_offset[0] = 6;
1191 layout.dac_gain[0] = 7;
1192 layout.dac_gain_fine[ 0 ] = 11;
1193 layout.dac_linearity[0] = 10;
1195 layout.dac_offset[ 1 ] = 9;
1196 layout.dac_gain[ 1 ] = 3;
1197 layout.dac_gain_fine[ 1 ] = 5;
1198 layout.dac_linearity[1] = 1;
1200 return cal_ni_generic( setup, &layout );
1203 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1204 const ni_caldac_layout_t *layout, unsigned int range )
1208 if( setup->old_calibration == NULL )
1210 reset_caldac( setup, layout->adc_pregain_offset );
1211 reset_caldac( setup, layout->adc_postgain_offset );
1212 reset_caldac( setup, layout->adc_gain );
1213 reset_caldac( setup, layout->adc_pregain_offset_fine );
1214 reset_caldac( setup, layout->adc_postgain_offset_fine );
1215 reset_caldac( setup, layout->adc_gain_fine );
1216 reset_caldac( setup, layout->adc_unip_offset );
1217 reset_caldac( setup, layout->adc_unip_offset_fine );
1220 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1221 0, range, AREF_GROUND, setup->old_calibration );
1224 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1225 reset_caldac( setup, layout->adc_pregain_offset );
1226 reset_caldac( setup, layout->adc_postgain_offset );
1227 reset_caldac( setup, layout->adc_gain );
1228 reset_caldac( setup, layout->adc_pregain_offset_fine );
1229 reset_caldac( setup, layout->adc_postgain_offset_fine );
1230 reset_caldac( setup, layout->adc_gain_fine );
1231 reset_caldac( setup, layout->adc_unip_offset );
1232 reset_caldac( setup, layout->adc_unip_offset_fine );
1237 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1238 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1242 if( setup->da_subdev < 0 ) return;
1244 if( setup->old_calibration == NULL )
1246 reset_caldac( setup, layout->dac_offset[ channel ] );
1247 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1248 reset_caldac( setup, layout->dac_gain[ channel ] );
1249 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1250 reset_caldac( setup, layout->dac_linearity[ channel ] );
1253 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1254 channel, range, AREF_GROUND, setup->old_calibration );
1257 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1258 reset_caldac( setup, layout->dac_offset[ channel ] );
1259 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1260 reset_caldac( setup, layout->dac_gain[ channel ] );
1261 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1262 reset_caldac( setup, layout->dac_linearity[ channel ] );
1267 static void prep_adc_for_dac( calibration_setup_t *setup, int observable )
1269 unsigned int adc_range;
1272 if( observable < 0 ) return;
1274 chanspec = setup->observables[ observable ].observe_insn.chanspec;
1275 adc_range = CR_RANGE( chanspec );
1277 comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1278 0, adc_range, 0, setup->new_calibration );
1281 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1283 comedi_calibration_setting_t *current_cal;
1287 int ai_unipolar_lowgain, ai_bipolar_lowgain;
1289 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
1290 assert( num_ai_ranges > 0 );
1292 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
1293 ai_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev );
1295 prep_adc_caldacs_generic( setup, layout, ai_bipolar_lowgain );
1297 current_cal = sc_alloc_calibration_setting( setup );
1298 current_cal->subdevice = setup->ad_subdev;
1299 reset_caldac( setup, layout->adc_gain_fine );
1300 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1301 ni_reference_low, layout->adc_gain );
1302 reset_caldac( setup, layout->adc_postgain_offset_fine );
1303 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1304 ni_zero_offset_high, layout->adc_postgain_offset );
1305 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1306 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1307 reset_caldac( setup, layout->adc_pregain_offset_fine );
1308 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1309 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1310 ni_reference_low, layout->adc_gain_fine );
1311 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1312 layout->adc_pregain_offset_fine );
1313 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1314 sc_push_aref( current_cal, SC_ALL_AREFS );
1315 if( layout->adc_unip_offset >= 0 )
1317 sc_push_range( current_cal, SC_ALL_RANGES );
1320 for( range = 0; range < num_ai_ranges; range++ )
1322 if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
1323 sc_push_range( current_cal, range );
1327 /* do seperate unipolar calibration if appropriate */
1328 if( ai_unipolar_lowgain >= 0 )
1330 current_cal = sc_alloc_calibration_setting( setup );
1331 current_cal->subdevice = setup->ad_subdev;
1332 if( layout->adc_unip_offset >= 0 )
1334 reset_caldac( setup, layout->adc_unip_offset_fine );
1335 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1336 layout->adc_unip_offset );
1337 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1338 layout->adc_unip_offset_fine );
1339 /* if we don't have a unipolar offset caldac, do a fully
1340 * independent calibration for unipolar ranges */
1343 prep_adc_caldacs_generic( setup, layout, ai_unipolar_lowgain );
1344 generic_peg( setup, ni_unip_zero_offset_low,
1345 layout->adc_pregain_offset, 1 );
1346 generic_peg( setup, ni_unip_zero_offset_low,
1347 layout->adc_postgain_offset, 1 );
1348 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1349 ni_unip_reference_low, layout->adc_gain );
1350 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1351 ni_unip_zero_offset_high, layout->adc_postgain_offset );
1352 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1353 ni_unip_zero_offset_high, layout->adc_postgain_offset_fine );
1354 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1355 layout->adc_pregain_offset );
1356 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1357 ni_unip_reference_low, layout->adc_gain_fine );
1358 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1359 layout->adc_pregain_offset_fine );
1361 for( range = 0; range < num_ai_ranges; range++ )
1363 if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
1364 sc_push_range( current_cal, range );
1366 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1367 sc_push_aref( current_cal, SC_ALL_AREFS );
1369 if( setup->da_subdev >= 0 && setup->do_output )
1371 unsigned int channel, range;
1372 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1373 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1376 for( channel = 0; channel < 2; channel++ )
1378 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1379 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1380 prep_adc_for_dac( setup, ni_ao_reference( channel ) );
1382 current_cal = sc_alloc_calibration_setting( setup );
1383 current_cal->subdevice = setup->da_subdev;
1384 generic_do_linearity( setup, current_cal, ni_ao_zero_offset( channel ),
1385 ni_ao_mid_linearity( channel ), ni_ao_reference( channel ),
1386 layout->dac_linearity[ channel ] );
1387 reset_caldac(setup, layout->dac_offset_fine[channel]);
1388 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1389 layout->dac_offset[ channel ] );
1390 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1391 layout->dac_offset_fine[ channel ] );
1392 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1393 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1394 layout->dac_gain[ channel ] );
1395 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1396 layout->dac_gain_fine[ channel ] );
1397 sc_push_channel( current_cal, channel );
1398 for( range = 0; range < num_ao_ranges; range++ )
1400 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1401 sc_push_range( current_cal, range );
1403 sc_push_aref( current_cal, SC_ALL_AREFS );
1405 if( ao_unipolar_lowgain >= 0 )
1407 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1409 current_cal = sc_alloc_calibration_setting( setup );
1410 current_cal->subdevice = setup->da_subdev;
1411 generic_do_linearity( setup, current_cal, ni_ao_unip_low_linearity( channel ),
1412 ni_ao_unip_mid_linearity( channel ), ni_ao_unip_reference( channel ),
1413 layout->dac_linearity[ channel ] );
1414 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1415 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1416 layout->dac_offset[ channel ] );
1417 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1418 layout->dac_offset_fine[ channel ] );
1419 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1420 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1421 layout->dac_gain[ channel ] );
1422 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1423 layout->dac_gain_fine[ channel ] );
1424 sc_push_channel( current_cal, channel );
1425 for( range = 0; range < num_ao_ranges; range++ )
1427 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1428 sc_push_range( current_cal, range );
1430 sc_push_aref( current_cal, SC_ALL_AREFS );
1435 retval = write_calibration_file( setup );
1440 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1446 lsb=read_eeprom( setup, lsb_loc );
1447 msb=read_eeprom( setup, msb_loc );
1448 assert( lsb >=0 && msb >= 0 );
1449 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1451 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1452 ref=5.000+1.0e-6*uv;
1453 DPRINT(0, "resulting reference voltage: %g\n", ref );
1454 if( fabs( ref - 5.0 ) > 0.005 )
1455 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1456 "from 5V. Possible bad eeprom address?\n" );
1462 NI 671x and 673x support
1465 static const int channels_per_ad8804 = 16;
1467 static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel)
1469 int ad8804_gain_channels[4] = {8, 2, 11, 5};
1470 int caldac_channel = ad8804_gain_channels[ao_channel % 4];
1471 int caldac_index = ao_channel / 4;
1472 /* just guessing that second ad8804 is works for ao channels 4-7
1473 * the same as the first ad8804 works for ao channels 0-3 */
1474 return caldac_index * channels_per_ad8804 + caldac_channel;
1476 static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel)
1478 int ad8804_linearity_channels[4] = {4, 10, 1, 0};
1479 int caldac_channel = ad8804_linearity_channels[ao_channel % 4];
1480 int caldac_index = ao_channel / 4;
1482 return caldac_index * channels_per_ad8804 + caldac_channel;
1484 static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel)
1486 int ad8804_offset_channels[4] = {7, 6, 9, 3};
1487 int caldac_channel = ad8804_offset_channels[ao_channel % 4];
1488 int caldac_index = ao_channel / 4;
1490 return caldac_index * channels_per_ad8804 + caldac_channel;
1493 static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup,
1494 unsigned int channel, unsigned int ao_range )
1496 return 3 * channel + 0;
1499 static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup,
1500 unsigned int channel, unsigned int ao_range )
1502 return 3 * channel + 1;
1505 static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup,
1506 unsigned int channel, unsigned int ao_range )
1508 return 3 * channel + 2;
1511 static const double ni67xx_unitless_adc_offset = 0.5;
1513 /* determine conversion factor between actual voltage and
1514 * interval [0,1) returned by reads from the calibration adc
1517 static double ni67xx_unitless_adc_slope(calibration_setup_t *setup)
1519 double reference_in_volts;
1520 double reference_unitless;
1524 comedi_range *range;
1525 static const int maxdata = 0x10000;
1528 if(ni_board(setup)->ref_eeprom_lsb >= 0 &&
1529 ni_board(setup)->ref_eeprom_msb >= 0)
1531 reference_in_volts = ni_get_reference(setup,
1532 ni_board(setup)->ref_eeprom_lsb, ni_board(setup)->ref_eeprom_msb );
1535 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
1536 "correction. This might be fixable if you send us an eeprom dump\n"
1537 "(see the demo/eeprom_dump program).\n");
1538 reference_in_volts = 5.0;
1541 memset(&insn, 0, sizeof(insn));
1542 insn.insn = INSN_READ;
1544 insn.subdev = setup->ad_subdev;
1546 insn.chanspec = CR_PACK(0, 0, AREF_GROUND) | CR_ALT_SOURCE;
1547 retval = comedi_do_insn(setup->dev, &insn);
1548 assert(retval >= 0);
1550 range = comedi_get_range(setup->dev, setup->ad_subdev, 0, 0);
1552 reference_unitless = comedi_to_phys(data, range, maxdata);
1554 slope = (reference_unitless - ni67xx_unitless_adc_offset) / reference_in_volts;
1559 /* calibration adc uses RANGE_UNKNOWN, so it will return a value from
1560 0.0 to 1.0 instead of a voltage, so we need to renormalize. */
1561 static void ni67xx_set_target( calibration_setup_t *setup, int obs, double target, double slope)
1563 set_target(setup, obs, target);
1564 /* convert target from volts to interval [0,1) which calibration
1566 setup->observables[obs].target *= slope;
1567 setup->observables[obs].target += ni67xx_unitless_adc_offset;
1570 static void ni67xx_setup_observables( calibration_setup_t *setup )
1572 comedi_insn tmpl, po_tmpl;
1574 int num_ao_channels;
1578 slope = ni67xx_unitless_adc_slope(setup);
1580 /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */
1581 setup->sv_order = 1;
1583 num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev);
1584 assert(num_ao_channels >= 0);
1586 memset( &tmpl, 0, sizeof(tmpl) );
1587 tmpl.insn = INSN_READ;
1589 tmpl.subdev = setup->ad_subdev;
1591 memset( &po_tmpl, 0, sizeof(po_tmpl) );
1592 po_tmpl.insn = INSN_WRITE;
1594 po_tmpl.subdev = setup->da_subdev;
1596 setup->n_observables = 0;
1598 for(i = 0; i < num_ao_channels; i++)
1600 o = setup->observables + ni67xx_ao_ground_observable_index( setup,
1602 o->reference_source = -1;
1603 assert( o->name == NULL );
1604 asprintf(&o->name, "dac%i ground, ground referenced", i);
1605 o->preobserve_insn = po_tmpl;
1606 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1607 o->preobserve_insn.data = o->preobserve_data;
1608 o->observe_insn = tmpl;
1609 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1610 ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0, slope);
1611 setup->n_observables++;
1613 o = setup->observables + ni67xx_ao_mid_observable_index( setup,
1615 o->reference_source = -1;
1616 assert( o->name == NULL );
1617 asprintf(&o->name, "dac%i mid, ground referenced", i);
1618 o->preobserve_insn = po_tmpl;
1619 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1620 o->preobserve_insn.data = o->preobserve_data;
1621 o->observe_insn = tmpl;
1622 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1623 ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0, slope);
1624 setup->n_observables++;
1626 o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0);
1627 o->reference_source = -1;
1628 assert( o->name == NULL );
1629 asprintf(&o->name, "dac%i high, ground referenced", i);
1630 o->preobserve_insn = po_tmpl;
1631 o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND );
1632 o->preobserve_insn.data = o->preobserve_data;
1633 o->observe_insn = tmpl;
1634 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1635 ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0, slope);
1636 setup->n_observables++;
1642 static int cal_ni_pci_6711(calibration_setup_t *setup)
1644 generic_layout_t layout;
1646 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE(0, 7, 69))
1648 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1649 "for this calibration to work properly\n" );
1651 init_generic_layout( &layout );
1652 layout.dac_gain = ni67xx_ao_gain_caldac;
1653 layout.dac_linearity = ni67xx_ao_linearity_caldac;
1654 layout.dac_offset = ni67xx_ao_offset_caldac;
1655 layout.dac_high_observable = ni67xx_ao_high_observable_index;
1656 layout.dac_mid_observable = ni67xx_ao_mid_observable_index;
1657 layout.dac_ground_observable = ni67xx_ao_ground_observable_index;
1658 layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 );
1659 return generic_cal_ao(setup, &layout);