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_SOME, 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_GUESS, 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, -1, -1 },
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-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
97 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
98 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
99 { "pci-6031e", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
100 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
101 { "pci-6033e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1b7, 0x1b8 },
102 { "pci-6034e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
103 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
104 { "pci-6036e", STATUS_DONE, cal_ni_pci_6036e, ni_setup_observables, 0x1ab, 0x1ac },
105 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
106 { "pci-6071e", STATUS_DONE, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
107 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
108 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
109 { "pxi-6025e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
110 { "pxi-6030e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
111 { "pxi-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
112 { "pxi-6040e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
113 { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
114 { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
115 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
116 { "pci-6711", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
117 { "pci-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
118 { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
119 { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
120 { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
121 { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
122 { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
123 { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
125 { "at-mio-64e-3", cal_ni_16e_1 },
128 #define n_boards (sizeof(boards)/sizeof(boards[0]))
130 static const int ni_num_observables = 20;
132 ni_zero_offset_low = 0,
135 ni_unip_zero_offset_low,
136 ni_unip_zero_offset_high,
137 ni_unip_reference_low,
144 ni_ao0_unip_zero_offset,
145 ni_ao0_unip_reference,
146 ni_ao0_unip_low_linearity,
147 ni_ao0_unip_mid_linearity,
148 ni_ao1_unip_zero_offset,
149 ni_ao1_unip_reference,
150 ni_ao1_unip_low_linearity,
151 ni_ao1_unip_mid_linearity,
153 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
155 if( channel ) return ni_ao1_zero_offset;
156 else return ni_ao0_zero_offset;
158 static inline unsigned int ni_ao_reference( unsigned int channel )
160 if( channel ) return ni_ao1_reference;
161 else return ni_ao0_reference;
163 static inline unsigned int ni_ao_mid_linearity( unsigned int channel )
165 if( channel ) return ni_ao1_linearity;
166 else return ni_ao0_linearity;
168 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
170 if( channel ) return ni_ao1_unip_zero_offset;
171 else return ni_ao0_unip_zero_offset;
173 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
175 if( channel ) return ni_ao1_unip_reference;
176 else return ni_ao0_unip_reference;
178 static inline unsigned int ni_ao_unip_low_linearity( unsigned int channel )
180 if( channel ) return ni_ao1_unip_low_linearity;
181 else return ni_ao0_unip_low_linearity;
183 static inline unsigned int ni_ao_unip_mid_linearity( unsigned int channel )
185 if( channel ) return ni_ao1_unip_mid_linearity;
186 else return ni_ao0_unip_mid_linearity;
189 static const int num_ao_observables_611x = 4;
190 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
191 unsigned int channel, unsigned int range ) {
192 assert( range == 0 );
195 static int ni_ao_reference_611x( const calibration_setup_t *setup,
196 unsigned int channel, unsigned int range ) {
197 assert( range == 0 );
198 return 2 * channel + 1;
200 static int ni_zero_offset_611x( const calibration_setup_t *setup,
201 unsigned int channel, unsigned int range ) {
202 return num_ao_observables_611x + 8 * range + 2 * channel;
204 static int ni_reference_611x( const calibration_setup_t *setup,
205 unsigned int channel, unsigned int range ) {
206 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
209 enum reference_sources {
214 REF_CALSRC_CALSRC = 4,
219 static inline unsigned int REF_DAC_GND( unsigned int channel )
221 if( channel ) return REF_DAC1_GND;
222 else return REF_DAC0_GND;
224 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
226 if( channel ) return REF_DAC1_CALSRC;
227 else return REF_DAC0_CALSRC;
230 static struct board_struct* ni_board( calibration_setup_t *setup )
232 return setup->private_data;
237 int adc_pregain_offset;
238 int adc_postgain_offset;
240 int adc_pregain_offset_fine;
241 int adc_postgain_offset_fine;
244 int adc_unip_offset_fine;
247 int dac_gain_fine[ 2 ];
248 int dac_linearity[ 2 ];
249 } ni_caldac_layout_t;
251 static int cal_ni_generic( calibration_setup_t *setup,
252 const ni_caldac_layout_t *layout );
254 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
258 layout->adc_pregain_offset = -1;
259 layout->adc_postgain_offset = -1;
260 layout->adc_gain = -1;
261 layout->adc_unip_offset = -1;
262 layout->adc_unip_offset_fine = -1;
263 layout->adc_pregain_offset_fine = -1;
264 layout->adc_postgain_offset_fine = -1;
265 layout->adc_gain_fine = -1;
266 for( i = 0; i < 2; i++ )
268 layout->dac_offset[ i ] = -1;
269 layout->dac_gain[ i ] = -1;
270 layout->dac_gain_fine[ i ] = -1;
271 layout->dac_linearity[ i ] = -1;
275 int ni_setup( calibration_setup_t *setup , const char *device_name )
279 retval = ni_setup_board( setup, device_name );
280 if( retval < 0 ) return retval;
281 setup_caldacs( setup, setup->caldac_subdev );
286 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
290 for(i = 0; i < n_boards; i++ ){
291 if(!strcmp( device_name, boards[i].name )){
292 setup->status = boards[i].status;
293 setup->do_cal = boards[i].cal;
294 setup->private_data = &boards[ i ];
295 boards[i].setup_observables( setup );
299 if( i == n_boards ) return -1;
303 static void ni_setup_ao_observables( calibration_setup_t *setup )
306 comedi_insn tmpl, po_tmpl;
307 unsigned int channel;
308 int ai_bipolar_lowgain;
309 int ao_bipolar_lowgain;
310 int ao_unipolar_lowgain;
312 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
313 assert(ai_bipolar_lowgain >= 0);
314 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
315 assert(ao_bipolar_lowgain >= 0);
316 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
318 memset(&tmpl,0,sizeof(tmpl));
319 tmpl.insn = INSN_READ;
321 tmpl.subdev = setup->ad_subdev;
323 memset(&po_tmpl, 0, sizeof(po_tmpl));
324 po_tmpl.insn = INSN_WRITE;
326 po_tmpl.subdev = setup->da_subdev;
328 for( channel = 0; channel < 2; channel++ )
331 o = setup->observables + ni_ao_zero_offset( channel );
332 assert( o->name == NULL );
333 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
334 o->preobserve_insn = po_tmpl;
335 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
336 o->preobserve_insn.data = o->preobserve_data;
337 o->observe_insn = tmpl;
338 o->observe_insn.chanspec =
339 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
340 | CR_ALT_SOURCE | CR_ALT_FILTER;
341 o->reference_source = REF_DAC_GND( channel );
342 set_target( setup, ni_ao_zero_offset( channel ),0.0);
345 o = setup->observables + ni_ao_reference( channel );
346 assert( o->name == NULL );
347 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
348 o->preobserve_insn = po_tmpl;
349 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
350 o->preobserve_insn.data = o->preobserve_data;
351 o->observe_insn = tmpl;
352 o->observe_insn.chanspec =
353 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
354 | CR_ALT_SOURCE | CR_ALT_FILTER;
355 o->reference_source = REF_DAC_GND( channel );
356 set_target( setup, ni_ao_reference( channel ),8.0);
358 /* ao linearity, mid */
359 o = setup->observables + ni_ao_mid_linearity( channel );
360 assert( o->name == NULL );
361 asprintf( &o->name, "ao %i, linearity (mid), low gain", channel );
362 o->preobserve_insn = po_tmpl;
363 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
364 o->preobserve_insn.data = o->preobserve_data;
365 o->observe_insn = tmpl;
366 o->observe_insn.chanspec =
367 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
368 | CR_ALT_SOURCE | CR_ALT_FILTER;
369 o->reference_source = REF_DAC_GND( channel );
370 set_target( setup, ni_ao_mid_linearity( channel ),4.0);
372 if( ao_unipolar_lowgain >= 0 )
374 /* ao unipolar zero offset */
375 o = setup->observables + ni_ao_unip_zero_offset( channel );
376 assert( o->name == NULL );
377 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
378 o->preobserve_insn = po_tmpl;
379 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
380 o->preobserve_insn.data = o->preobserve_data;
381 o->observe_insn = tmpl;
382 o->observe_insn.chanspec =
383 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
384 | CR_ALT_SOURCE | CR_ALT_FILTER;
385 o->reference_source = REF_DAC_GND( channel );
386 set_target( setup, ni_ao_unip_zero_offset( channel ),0.0);
388 /* ao unipolar gain */
389 o = setup->observables + ni_ao_unip_reference( channel );
390 assert( o->name == NULL );
391 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
392 o->preobserve_insn = po_tmpl;
393 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
394 o->preobserve_insn.data = o->preobserve_data;
395 o->observe_insn = tmpl;
396 o->observe_insn.chanspec =
397 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
398 | CR_ALT_SOURCE | CR_ALT_FILTER;
399 o->reference_source = REF_DAC_GND( channel );
400 set_target( setup, ni_ao_unip_reference( channel ), 9.0);
402 /* ao unipolar linearity, mid */
403 o = setup->observables + ni_ao_unip_mid_linearity( channel );
404 assert( o->name == NULL );
405 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
406 o->preobserve_insn = po_tmpl;
407 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
408 o->preobserve_insn.data = o->preobserve_data;
409 o->observe_insn = tmpl;
410 o->observe_insn.chanspec =
411 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
412 | CR_ALT_SOURCE | CR_ALT_FILTER;
413 o->reference_source = REF_DAC_GND( channel );
414 set_target( setup, ni_ao_unip_mid_linearity( channel ), 5.0);
416 /* ao unipolar linearity, low */
417 o = setup->observables + ni_ao_unip_low_linearity( channel );
418 assert( o->name == NULL );
419 asprintf( &o->name, "ao %i, unipolar linearity (low), low gain", channel );
420 o->preobserve_insn = po_tmpl;
421 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
422 o->preobserve_insn.data = o->preobserve_data;
423 o->observe_insn = tmpl;
424 o->observe_insn.chanspec =
425 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
426 | CR_ALT_SOURCE | CR_ALT_FILTER;
427 o->reference_source = REF_DAC_GND( channel );
428 set_target( setup, ni_ao_unip_low_linearity( channel ), 1.0);
433 static void ni_setup_observables( calibration_setup_t *setup )
437 int bipolar_highgain;
438 int unipolar_lowgain;
439 int unipolar_highgain;
440 double voltage_reference;
443 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
444 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
445 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
446 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
448 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
449 ni_board( setup )->ref_eeprom_msb >= 0 )
451 voltage_reference = ni_get_reference( setup,
452 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
455 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
456 "correction. This might be fixable if you send us an eeprom dump\n"
457 "(see the demo/eeprom_dump program).\n");
458 voltage_reference = 5.0;
461 memset(&tmpl,0,sizeof(tmpl));
462 tmpl.insn = INSN_READ;
464 tmpl.subdev = setup->ad_subdev;
466 setup->n_observables = ni_num_observables;
468 /* 0 offset, low gain */
469 o = setup->observables + ni_zero_offset_low;
470 o->name = "ai, bipolar zero offset, low gain";
471 o->observe_insn = tmpl;
472 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
473 | CR_ALT_SOURCE | CR_ALT_FILTER;
474 o->reference_source = REF_GND_GND;
477 /* 0 offset, high gain */
478 o = setup->observables + ni_zero_offset_high;
479 o->name = "ai, bipolar zero offset, high gain";
480 o->observe_insn = tmpl;
481 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
482 | CR_ALT_SOURCE | CR_ALT_FILTER;
483 o->reference_source = REF_GND_GND;
486 /* voltage reference */
487 o = setup->observables + ni_reference_low;
488 o->name = "ai, bipolar voltage reference, low gain";
489 o->observe_insn = tmpl;
490 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
491 | CR_ALT_SOURCE | CR_ALT_FILTER;
492 o->reference_source = REF_CALSRC_GND;
493 o->target = voltage_reference;
495 if(unipolar_lowgain>=0){
496 o = setup->observables + ni_unip_zero_offset_low;
497 o->name = "ai, unipolar zero offset, low gain";
498 o->observe_insn = tmpl;
499 o->observe_insn.chanspec =
500 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
501 | CR_ALT_SOURCE | CR_ALT_FILTER;
502 o->reference_source = REF_GND_GND;
503 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
505 o = setup->observables + ni_unip_reference_low;
506 o->name = "ai, unipolar voltage reference, low gain";
507 o->observe_insn = tmpl;
508 o->observe_insn.chanspec =
509 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
510 | CR_ALT_SOURCE | CR_ALT_FILTER;
511 o->reference_source = REF_CALSRC_GND;
512 o->target = voltage_reference;
515 if(unipolar_highgain >= 0)
517 o = setup->observables + ni_unip_zero_offset_high;
518 o->name = "ai, unipolar zero offset, high gain";
519 o->observe_insn = tmpl;
520 o->observe_insn.chanspec =
521 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
522 | CR_ALT_SOURCE | CR_ALT_FILTER;
523 o->reference_source = REF_GND_GND;
524 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
527 if(setup->da_subdev >= 0)
528 ni_setup_ao_observables( setup );
531 /* for +-50V and +-20V ranges, the reference source goes 0V
532 * to 50V instead of 0V to 5V */
533 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
537 bits = 200.0 * ( *voltage / reference );
538 if( bits > 200 ) bits = 200;
539 if( bits < 0 ) bits = 0;
541 *voltage = reference * ( bits / 200.0 );
545 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
547 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
550 static void reference_target_611x( calibration_setup_t *setup,
551 observable *o, double master_reference, unsigned int range )
553 int cal_gain_reg_bits;
556 comedi_range *range_ptr;
558 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
559 assert( range_ptr != NULL );
560 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
561 else reference = master_reference;
562 target = range_ptr->max * 0.8;
564 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
566 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
570 static void ni_setup_observables_611x( calibration_setup_t *setup )
575 double master_reference;
577 int num_ai_channels, num_ai_ranges;
578 static const int num_ao_channels = 2;
580 setup->sv_settling_time_ns = 10000000;
581 setup->sv_order = 14;
583 master_reference = ni_get_reference( setup,
584 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
586 memset(&tmpl,0,sizeof(tmpl));
587 tmpl.insn = INSN_READ;
589 tmpl.subdev = setup->ad_subdev;
591 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
592 assert( num_ai_channels >= 0 );
593 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
594 assert( num_ai_ranges >= 0 );
596 for( channel = 0; channel < num_ai_channels; channel++ )
598 for( range = 0; range < num_ai_ranges; range++ )
601 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
602 assert( o->name == NULL );
603 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
605 o->observe_insn = tmpl;
606 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
607 | CR_ALT_SOURCE | CR_ALT_FILTER;
608 o->reference_source = REF_GND_GND;
611 /* voltage reference */
612 o = setup->observables + ni_reference_611x( setup, channel, range );
613 assert( o->name == NULL );
614 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
616 o->observe_insn = tmpl;
617 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
618 | CR_ALT_SOURCE | CR_ALT_FILTER;
619 reference_target_611x( setup, o, master_reference, range );
623 memset(&po_tmpl,0,sizeof(po_tmpl));
624 po_tmpl.insn = INSN_WRITE;
626 po_tmpl.subdev = setup->da_subdev;
628 for( channel = 0; channel < num_ao_channels; channel ++ )
630 static const int ai_range_for_ao = 2;
633 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
634 assert( o->name == NULL );
635 asprintf( &o->name, "ao ch %i, zero offset", channel );
636 o->preobserve_insn = po_tmpl;
637 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
638 o->preobserve_insn.data = o->preobserve_data;
639 o->observe_insn = tmpl;
640 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
641 | CR_ALT_SOURCE | CR_ALT_FILTER;
642 o->reference_source = REF_DAC_GND( channel );
643 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
646 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
647 assert( o->name == NULL );
648 asprintf( &o->name, "ao ch %i, reference voltage", channel );
649 o->preobserve_insn = po_tmpl;
650 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
651 o->preobserve_insn.data = o->preobserve_data;
652 o->observe_insn = tmpl;
653 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
654 | CR_ALT_SOURCE | CR_ALT_FILTER;
655 o->reference_source = REF_DAC_GND( channel );
656 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
659 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
662 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
664 ni_caldac_layout_t layout;
666 init_ni_caldac_layout( &layout );
667 layout.adc_pregain_offset = 8;
668 layout.adc_postgain_offset = 2;
670 layout.adc_gain_fine = 1;
672 return cal_ni_generic( setup, &layout );
675 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
677 ni_caldac_layout_t layout;
679 init_ni_caldac_layout( &layout );
680 layout.adc_pregain_offset = 8;
681 layout.adc_postgain_offset = 2;
683 layout.adc_gain_fine = 1;
684 layout.dac_offset[ 0 ] = 6;
685 layout.dac_gain[ 0 ] = 4;
686 layout.dac_offset[ 1 ] = 7;
687 layout.dac_gain[ 1 ] = 5;
689 return cal_ni_generic( setup, &layout );
692 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
694 ni_caldac_layout_t layout;
696 init_ni_caldac_layout( &layout );
697 layout.adc_pregain_offset = 8;
698 layout.adc_postgain_offset = 2;
699 layout.adc_postgain_offset_fine = 3;
701 layout.adc_gain_fine = 1;
702 layout.dac_offset[ 0 ] = 6;
703 layout.dac_gain[ 0 ] = 4;
704 layout.dac_offset[ 1 ] = 7;
705 layout.dac_gain[ 1 ] = 5;
707 return cal_ni_generic( setup, &layout );
710 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
712 ni_caldac_layout_t layout;
714 init_ni_caldac_layout( &layout );
715 layout.adc_pregain_offset = 0;
716 layout.adc_postgain_offset = 1;
718 layout.adc_unip_offset = 2;
719 layout.dac_offset[0] = 5;
720 layout.dac_gain[0] = 6;
721 layout.dac_linearity[0] = 4;
722 layout.dac_offset[1] = 8;
723 layout.dac_gain[1] = 9;
724 layout.dac_linearity[1] = 7;
726 return cal_ni_generic( setup, &layout );
729 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
731 return cal_ni_at_mio_16e_1(setup);
734 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
736 ni_caldac_layout_t layout;
738 init_ni_caldac_layout( &layout );
739 layout.adc_pregain_offset = 0;
740 layout.adc_postgain_offset = 1;
741 layout.adc_unip_offset = 2;
743 layout.dac_offset[ 0 ] = 5;
744 layout.dac_gain[ 0 ] = 6;
745 layout.dac_linearity[ 0 ] = 4;
746 layout.dac_offset[ 1 ] = 8;
747 layout.dac_gain[ 1 ] = 9;
748 layout.dac_linearity[ 1 ] = 7;
750 return cal_ni_generic( setup, &layout );
753 static int cal_ni_pci_6032e(calibration_setup_t *setup)
755 ni_caldac_layout_t layout;
757 init_ni_caldac_layout( &layout );
758 layout.adc_pregain_offset = 8;
759 layout.adc_postgain_offset = 2;
760 layout.adc_postgain_offset_fine = 3;
762 layout.adc_gain_fine = 1;
764 return cal_ni_generic( setup, &layout );
767 static int cal_ni_pci_6035e(calibration_setup_t *setup)
769 /* this is for the ad8804_debug caldac */
770 ni_caldac_layout_t layout;
772 init_ni_caldac_layout( &layout );
773 layout.adc_pregain_offset = 0;
774 layout.adc_pregain_offset_fine = 8;
775 layout.adc_postgain_offset = 4;
777 layout.dac_offset[ 0 ] = 6;
778 layout.dac_gain[ 0 ] = 11;
779 layout.dac_linearity[ 0 ] = 10;
780 layout.dac_offset[ 1 ] = 9;
781 layout.dac_gain[ 1 ] = 5;
782 layout.dac_linearity[ 1 ] = 1;
784 return cal_ni_generic( setup, &layout );
787 static int cal_ni_pci_6036e(calibration_setup_t *setup)
789 ni_caldac_layout_t layout;
791 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
793 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
794 "for this calibration to work properly\n" );
797 /* this is for the ad8804_debug caldac */
798 init_ni_caldac_layout( &layout );
799 layout.adc_pregain_offset = 0;
800 layout.adc_postgain_offset = 4;
801 layout.adc_pregain_offset_fine = 8;
803 layout.dac_offset[ 0 ] = 6;
804 layout.dac_gain[ 0 ] = 7;
805 layout.dac_gain_fine[ 0 ] = 11;
806 layout.dac_linearity[ 0 ] = 10;
807 layout.dac_offset[ 1 ] = 9;
808 layout.dac_gain[ 1 ] = 3;
809 layout.dac_gain_fine[ 1 ] = 5;
810 layout.dac_linearity[ 1 ] = 1;
812 return cal_ni_generic( setup, &layout );
815 static int cal_ni_pci_6071e(calibration_setup_t *setup)
817 ni_caldac_layout_t layout;
819 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
821 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
822 "for this calibration to work properly\n" );
825 init_ni_caldac_layout( &layout );
826 layout.adc_pregain_offset = 8;
827 layout.adc_postgain_offset = 4;
828 layout.adc_unip_offset = 7;
830 layout.dac_offset[ 0 ] = 6;
831 layout.dac_gain[ 0 ] = 11;
832 layout.dac_linearity[ 0 ] = 10;
833 layout.dac_offset[ 1 ] = 9;
834 layout.dac_gain[ 1 ] = 5;
835 layout.dac_linearity[ 1 ] = 1;
836 return cal_ni_generic( setup, &layout );
839 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
841 ni_caldac_layout_t layout;
843 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
845 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
846 "for this calibration to work properly\n" );
849 init_ni_caldac_layout( &layout );
850 layout.adc_pregain_offset = 0;
851 layout.adc_pregain_offset_fine = 8;
852 layout.adc_postgain_offset = 4;
854 layout.dac_offset[ 0 ] = 6;
855 layout.dac_gain[ 0 ] = 11;
856 layout.dac_linearity[ 0 ] = 10;
857 layout.dac_offset[ 1 ] = 9;
858 layout.dac_gain[ 1 ] = 5;
859 layout.dac_linearity[ 1 ] = 1;
860 return cal_ni_generic( setup, &layout );
863 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
866 ni_caldac_layout_t layout;
868 init_ni_caldac_layout( &layout );
869 layout.adc_pregain_offset = 10;
870 layout.adc_pregain_offset_fine = 0;
871 layout.adc_postgain_offset = 1;
873 layout.adc_unip_offset = 2;
874 layout.dac_offset[ 0 ] = 5; /* guess */
875 layout.dac_gain[ 0 ] = 6; /* guess */
876 layout.dac_offset[ 1 ] = 8; /* guess */
877 layout.dac_gain[ 1 ] = 9; /* guess */
879 return cal_ni_generic( setup, &layout );
882 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
884 ni_caldac_layout_t layout;
886 init_ni_caldac_layout( &layout );
887 layout.adc_pregain_offset = 8;
888 layout.adc_postgain_offset = 2;
890 layout.adc_gain_fine = 1;
891 layout.adc_unip_offset = 7;
892 layout.dac_offset[ 0 ] = 6;
893 layout.dac_gain[ 0 ] = 4;
894 layout.dac_offset[ 1 ] = 7;
895 layout.dac_gain[ 1 ] = 5;
897 return cal_ni_generic( setup, &layout );
900 static int cal_ni_pci_6023e(calibration_setup_t *setup)
902 /* for comedi-0.7.65 */
903 ni_caldac_layout_t layout;
905 init_ni_caldac_layout( &layout );
906 layout.adc_pregain_offset = 8; /* possibly wrong */
907 layout.adc_pregain_offset_fine = 0;
908 layout.adc_postgain_offset = 4;
911 return cal_ni_generic( setup, &layout );
914 static int cal_ni_pci_6024e(calibration_setup_t *setup)
916 ni_caldac_layout_t layout;
918 init_ni_caldac_layout( &layout );
919 layout.adc_pregain_offset = 0;
920 layout.adc_postgain_offset = 4;
921 layout.adc_pregain_offset_fine = 8;
923 layout.dac_offset[ 0 ] = 6;
924 layout.dac_gain[ 0 ] = 11;
925 layout.dac_linearity[ 0 ] = 10;
926 layout.dac_offset[ 1 ] = 9;
927 layout.dac_gain[ 1 ] = 5;
928 layout.dac_linearity[ 1 ] = 1;
930 return cal_ni_generic( setup, &layout );
933 static int cal_ni_pci_6025e(calibration_setup_t *setup)
935 ni_caldac_layout_t layout;
937 init_ni_caldac_layout( &layout );
938 layout.adc_pregain_offset = 0;
939 layout.adc_postgain_offset = 4;
940 layout.adc_pregain_offset_fine = 8;
942 layout.dac_offset[ 0 ] = 6;
943 layout.dac_gain[ 0 ] = 11;
944 layout.dac_linearity[ 0 ] = 10;
945 layout.dac_offset[ 1 ] = 9;
946 layout.dac_gain[ 1 ] = 5;
947 layout.dac_linearity[ 1 ] = 1;
949 return cal_ni_generic( setup, &layout );
952 static int cal_ni_pci_6052e(calibration_setup_t *setup)
955 * This board has noisy caldacs
957 * The NI documentation says (true mb88341 addressing):
958 * 0, 8 AI pregain (coarse, fine)
961 * 14, 7 AI unipolar offset
967 * 10, 6 AO1 reference
970 * For us, these map to (ad8804 channels)
972 * 0, 1 AI pregain (coarse, fine)
975 * 7 AI unipolar offset
984 * or, with mb88341 channels
994 ni_caldac_layout_t layout;
996 init_ni_caldac_layout( &layout );
997 layout.adc_pregain_offset = 0;
998 layout.adc_postgain_offset = 2;
1000 layout.adc_unip_offset = 6;
1001 layout.adc_unip_offset_fine = 7;
1002 layout.adc_pregain_offset_fine = 1;
1003 layout.adc_postgain_offset_fine = 3;
1004 layout.adc_gain_fine = 5;
1006 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1007 "for this calibration to work properly\n" );
1008 /* this works when the first two caldacs are ad8804_debug */
1009 layout.dac_offset[ 0 ] = 16 + 3;
1010 layout.dac_gain[ 0 ] = 16 + 1;
1011 layout.dac_gain_fine[ 0 ] = 16 + 2;
1012 layout.dac_linearity[ 0 ] = 16 + 0;
1013 layout.dac_offset[ 1 ] = 16 + 7;
1014 layout.dac_gain[ 1 ] = 16 + 5;
1015 layout.dac_gain_fine[ 1 ] = 16 + 6;
1016 layout.dac_linearity[ 1 ] = 16 + 4;
1018 return cal_ni_generic( setup, &layout );
1021 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
1023 ni_caldac_layout_t layout;
1025 init_ni_caldac_layout( &layout );
1026 layout.adc_pregain_offset = 0;
1027 layout.adc_postgain_offset = 1;
1028 layout.adc_gain = 3;
1029 layout.adc_unip_offset = 2;
1031 return cal_ni_generic( setup, &layout );
1034 static int adc_offset_611x( unsigned int channel )
1036 return 2 * channel + 2;
1038 static int adc_gain_611x( unsigned int channel )
1040 return 2 * channel + 1;
1042 static int dac_offset_611x( unsigned int channel )
1044 return 12 + 2 + 2 * channel;
1046 static int dac_gain_611x( unsigned int channel )
1048 return 12 + 1 + 2 * channel;
1050 static int cal_ni_pci_611x( calibration_setup_t *setup )
1052 generic_layout_t layout;
1054 init_generic_layout( &layout );
1055 layout.adc_offset = adc_offset_611x;
1056 layout.adc_gain = adc_gain_611x;
1057 layout.dac_offset = dac_offset_611x;
1058 layout.dac_gain = dac_gain_611x;
1059 layout.adc_high_observable = ni_reference_611x;
1060 layout.adc_ground_observable = ni_zero_offset_611x;
1061 layout.dac_high_observable = ni_ao_reference_611x;
1062 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1064 return generic_cal_by_channel_and_range( setup, &layout );
1067 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1069 ni_caldac_layout_t layout;
1071 init_ni_caldac_layout( &layout );
1072 layout.adc_pregain_offset = 8;
1073 layout.adc_postgain_offset = 4;
1074 layout.adc_gain = 2;
1075 layout.adc_unip_offset = 7;
1076 layout.dac_offset[ 0 ] = 6;
1077 layout.dac_gain[ 0 ] = 11;
1078 layout.dac_linearity[ 0 ] = 10;
1079 layout.dac_offset[ 1 ] = 9;
1080 layout.dac_gain[ 1 ] = 5;
1081 layout.dac_linearity[ 1 ] = 1;
1083 return cal_ni_generic( setup, &layout );
1086 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1088 ni_caldac_layout_t layout;
1090 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1092 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1093 "for this calibration to work properly\n" );
1095 init_ni_caldac_layout( &layout );
1096 layout.adc_pregain_offset = 8;
1097 layout.adc_postgain_offset = 4;
1098 layout.adc_gain = 2;
1099 layout.adc_unip_offset = 7;
1100 layout.dac_offset[ 0 ] = 6;
1101 layout.dac_gain[ 0 ] = 11;
1102 layout.dac_linearity[ 0 ] = 10;
1103 layout.dac_offset[ 1 ] = 9;
1104 layout.dac_gain[ 1 ] = 5;
1105 layout.dac_linearity[ 1 ] = 1;
1107 return cal_ni_generic( setup, &layout );
1110 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1112 ni_caldac_layout_t layout;
1114 init_ni_caldac_layout( &layout );
1116 layout.adc_pregain_offset = 0;
1117 layout.adc_postgain_offset = 4;
1118 layout.adc_gain = 2;
1119 //layout.adc_unip_offset = 7;
1120 layout.dac_offset[ 0 ] = 6;
1121 layout.dac_gain[ 0 ] = 3;
1122 //layout.dac_linearity[ 0 ] = 10;
1123 layout.dac_offset[ 1 ] = 1;
1124 layout.dac_gain[ 1 ] = 5;
1125 //layout.dac_linearity[ 1 ] = 1;
1127 return cal_ni_generic( setup, &layout );
1130 static int cal_ni_daqcard_6036e( calibration_setup_t *setup )
1132 ni_caldac_layout_t layout;
1134 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 68 ) )
1136 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1137 "for this calibration to work properly\n" );
1140 init_ni_caldac_layout( &layout );
1142 layout.adc_pregain_offset = 0;
1143 layout.adc_postgain_offset = 4;
1144 layout.adc_gain = 2;
1146 layout.dac_offset[ 0 ] = 6;
1147 layout.dac_gain[ 0 ] = 7;
1148 // layout.dac_gain_fine[ 0 ] = XXX;
1150 layout.dac_offset[ 1 ] = 1;
1151 layout.dac_gain[ 1 ] = 3;
1152 layout.dac_gain_fine[ 1 ] = 5;
1154 return cal_ni_generic( setup, &layout );
1157 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1158 const ni_caldac_layout_t *layout, unsigned int range )
1162 if( setup->old_calibration == NULL )
1164 reset_caldac( setup, layout->adc_pregain_offset );
1165 reset_caldac( setup, layout->adc_postgain_offset );
1166 reset_caldac( setup, layout->adc_gain );
1167 reset_caldac( setup, layout->adc_pregain_offset_fine );
1168 reset_caldac( setup, layout->adc_postgain_offset_fine );
1169 reset_caldac( setup, layout->adc_gain_fine );
1170 reset_caldac( setup, layout->adc_unip_offset );
1171 reset_caldac( setup, layout->adc_unip_offset_fine );
1174 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1175 0, range, AREF_GROUND, setup->old_calibration );
1178 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1179 reset_caldac( setup, layout->adc_pregain_offset );
1180 reset_caldac( setup, layout->adc_postgain_offset );
1181 reset_caldac( setup, layout->adc_gain );
1182 reset_caldac( setup, layout->adc_pregain_offset_fine );
1183 reset_caldac( setup, layout->adc_postgain_offset_fine );
1184 reset_caldac( setup, layout->adc_gain_fine );
1185 reset_caldac( setup, layout->adc_unip_offset );
1186 reset_caldac( setup, layout->adc_unip_offset_fine );
1191 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1192 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1196 if( setup->da_subdev < 0 ) return;
1198 if( setup->old_calibration == NULL )
1200 reset_caldac( setup, layout->dac_offset[ channel ] );
1201 reset_caldac( setup, layout->dac_gain[ channel ] );
1202 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1203 reset_caldac( setup, layout->dac_linearity[ channel ] );
1206 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1207 channel, range, AREF_GROUND, setup->old_calibration );
1210 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1211 reset_caldac( setup, layout->dac_offset[ channel ] );
1212 reset_caldac( setup, layout->dac_gain[ channel ] );
1213 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1214 reset_caldac( setup, layout->dac_linearity[ channel ] );
1219 static void prep_adc_for_dac( calibration_setup_t *setup, int observable )
1221 unsigned int adc_range;
1224 if( observable < 0 ) return;
1226 chanspec = setup->observables[ observable ].observe_insn.chanspec;
1227 adc_range = CR_RANGE( chanspec );
1229 comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1230 0, adc_range, 0, setup->new_calibration );
1233 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1235 comedi_calibration_setting_t *current_cal;
1239 int ai_unipolar_lowgain, ai_bipolar_lowgain;
1241 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
1242 assert( num_ai_ranges > 0 );
1244 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
1245 ai_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev );
1247 prep_adc_caldacs_generic( setup, layout, ai_bipolar_lowgain );
1249 current_cal = sc_alloc_calibration_setting( setup );
1250 current_cal->subdevice = setup->ad_subdev;
1251 reset_caldac( setup, layout->adc_gain_fine );
1252 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1253 ni_reference_low, layout->adc_gain );
1254 reset_caldac( setup, layout->adc_postgain_offset_fine );
1255 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1256 ni_zero_offset_high, layout->adc_postgain_offset );
1257 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1258 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1259 reset_caldac( setup, layout->adc_pregain_offset_fine );
1260 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1261 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1262 ni_reference_low, layout->adc_gain_fine );
1263 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1264 layout->adc_pregain_offset_fine );
1265 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1266 sc_push_aref( current_cal, SC_ALL_AREFS );
1267 if( layout->adc_unip_offset >= 0 )
1269 sc_push_range( current_cal, SC_ALL_RANGES );
1272 for( range = 0; range < num_ai_ranges; range++ )
1274 if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
1275 sc_push_range( current_cal, range );
1279 /* do seperate unipolar calibration if appropriate */
1280 if( ai_unipolar_lowgain >= 0 )
1282 current_cal = sc_alloc_calibration_setting( setup );
1283 current_cal->subdevice = setup->ad_subdev;
1284 if( layout->adc_unip_offset >= 0 )
1286 reset_caldac( setup, layout->adc_unip_offset_fine );
1287 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1288 layout->adc_unip_offset );
1289 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1290 layout->adc_unip_offset_fine );
1291 /* if we don't have a unipolar offset caldac, do a fully
1292 * independent calibration for unipolar ranges */
1295 prep_adc_caldacs_generic( setup, layout, ai_unipolar_lowgain );
1296 generic_peg( setup, ni_unip_zero_offset_low,
1297 layout->adc_pregain_offset, 1 );
1298 generic_peg( setup, ni_unip_zero_offset_low,
1299 layout->adc_postgain_offset, 1 );
1300 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1301 ni_unip_reference_low, layout->adc_gain );
1302 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1303 ni_unip_zero_offset_high, layout->adc_postgain_offset );
1304 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1305 ni_unip_zero_offset_high, layout->adc_postgain_offset_fine );
1306 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1307 layout->adc_pregain_offset );
1308 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1309 ni_unip_reference_low, layout->adc_gain_fine );
1310 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1311 layout->adc_pregain_offset_fine );
1313 for( range = 0; range < num_ai_ranges; range++ )
1315 if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
1316 sc_push_range( current_cal, range );
1318 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1319 sc_push_aref( current_cal, SC_ALL_AREFS );
1321 if( setup->da_subdev >= 0 && setup->do_output )
1323 unsigned int channel, range;
1324 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1325 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1328 for( channel = 0; channel < 2; channel++ )
1330 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1331 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1332 prep_adc_for_dac( setup, ni_ao_reference( channel ) );
1334 current_cal = sc_alloc_calibration_setting( setup );
1335 current_cal->subdevice = setup->da_subdev;
1336 generic_do_linearity( setup, current_cal, ni_ao_zero_offset( channel ),
1337 ni_ao_mid_linearity( channel ), ni_ao_reference( channel ),
1338 layout->dac_linearity[ channel ] );
1339 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1340 layout->dac_offset[ channel ] );
1341 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1342 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1343 layout->dac_gain[ channel ] );
1344 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1345 layout->dac_gain_fine[ channel ] );
1346 sc_push_channel( current_cal, channel );
1347 for( range = 0; range < num_ao_ranges; range++ )
1349 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1350 sc_push_range( current_cal, range );
1352 sc_push_aref( current_cal, SC_ALL_AREFS );
1354 if( ao_unipolar_lowgain >= 0 )
1356 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1358 current_cal = sc_alloc_calibration_setting( setup );
1359 current_cal->subdevice = setup->da_subdev;
1360 generic_do_linearity( setup, current_cal, ni_ao_unip_low_linearity( channel ),
1361 ni_ao_unip_mid_linearity( channel ), ni_ao_unip_reference( channel ),
1362 layout->dac_linearity[ channel ] );
1363 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1364 layout->dac_offset[ channel ] );
1365 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1366 layout->dac_gain[ channel ] );
1367 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1368 layout->dac_gain_fine[ channel ] );
1369 sc_push_channel( current_cal, channel );
1370 for( range = 0; range < num_ao_ranges; range++ )
1372 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1373 sc_push_range( current_cal, range );
1375 sc_push_aref( current_cal, SC_ALL_AREFS );
1380 retval = write_calibration_file( setup );
1385 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1391 lsb=read_eeprom( setup, lsb_loc );
1392 msb=read_eeprom( setup, msb_loc );
1393 assert( lsb >=0 && msb >= 0 );
1394 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1396 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1397 ref=5.000+1.0e-6*uv;
1398 DPRINT(0, "resulting reference voltage: %g\n", ref );
1399 if( fabs( ref - 5.0 ) > 0.005 )
1400 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1401 "from 5V. Possible bad eeprom address?\n" );
1407 NI 671x and 673x support
1410 static const int channels_per_ad8804 = 16;
1412 static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel)
1414 int ad8804_gain_channels[4] = {8, 2, 11, 5};
1415 int caldac_channel = ad8804_gain_channels[ao_channel % 4];
1416 int caldac_index = ao_channel / 4;
1417 /* just guessing that second ad8804 is works for ao channels 4-7
1418 * the same as the first ad8804 works for ao channels 0-3 */
1419 return caldac_index * channels_per_ad8804 + caldac_channel;
1421 static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel)
1423 int ad8804_linearity_channels[4] = {4, 10, 1, 0};
1424 int caldac_channel = ad8804_linearity_channels[ao_channel % 4];
1425 int caldac_index = ao_channel / 4;
1427 return caldac_index * channels_per_ad8804 + caldac_channel;
1429 static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel)
1431 int ad8804_offset_channels[4] = {7, 6, 9, 3};
1432 int caldac_channel = ad8804_offset_channels[ao_channel % 4];
1433 int caldac_index = ao_channel / 4;
1435 return caldac_index * channels_per_ad8804 + caldac_channel;
1438 static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup,
1439 unsigned int channel, unsigned int ao_range )
1441 return 3 * channel + 0;
1444 static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup,
1445 unsigned int channel, unsigned int ao_range )
1447 return 3 * channel + 1;
1450 static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup,
1451 unsigned int channel, unsigned int ao_range )
1453 return 3 * channel + 2;
1456 static const double ni67xx_unitless_adc_offset = 0.5;
1458 /* determine conversion factor between actual voltage and
1459 * interval [0,1) returned by reads from the calibration adc
1462 static double ni67xx_unitless_adc_slope(calibration_setup_t *setup)
1464 double reference_in_volts;
1465 double reference_unitless;
1469 comedi_range *range;
1470 static const int maxdata = 0x10000;
1473 if(ni_board(setup)->ref_eeprom_lsb >= 0 &&
1474 ni_board(setup)->ref_eeprom_msb >= 0)
1476 reference_in_volts = ni_get_reference(setup,
1477 ni_board(setup)->ref_eeprom_lsb, ni_board(setup)->ref_eeprom_msb );
1480 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
1481 "correction. This might be fixable if you send us an eeprom dump\n"
1482 "(see the demo/eeprom_dump program).\n");
1483 reference_in_volts = 5.0;
1486 memset(&insn, 0, sizeof(insn));
1487 insn.insn = INSN_READ;
1489 insn.subdev = setup->ad_subdev;
1491 insn.chanspec = CR_PACK(0, 0, AREF_GROUND) | CR_ALT_SOURCE;
1492 retval = comedi_do_insn(setup->dev, &insn);
1493 assert(retval >= 0);
1495 range = comedi_get_range(setup->dev, setup->ad_subdev, 0, 0);
1497 reference_unitless = comedi_to_phys(data, range, maxdata);
1499 slope = (reference_unitless - ni67xx_unitless_adc_offset) / reference_in_volts;
1504 /* calibration adc uses RANGE_UNKNOWN, so it will return a value from
1505 0.0 to 1.0 instead of a voltage, so we need to renormalize. */
1506 static void ni67xx_set_target( calibration_setup_t *setup, int obs, double target, double slope)
1508 set_target(setup, obs, target);
1509 /* convert target from volts to interval [0,1) which calibration
1511 setup->observables[obs].target *= slope;
1512 setup->observables[obs].target += ni67xx_unitless_adc_offset;
1515 static void ni67xx_setup_observables( calibration_setup_t *setup )
1517 comedi_insn tmpl, po_tmpl;
1519 int num_ao_channels;
1523 slope = ni67xx_unitless_adc_slope(setup);
1525 /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */
1526 setup->sv_order = 1;
1528 num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev);
1529 assert(num_ao_channels >= 0);
1531 memset( &tmpl, 0, sizeof(tmpl) );
1532 tmpl.insn = INSN_READ;
1534 tmpl.subdev = setup->ad_subdev;
1536 memset( &po_tmpl, 0, sizeof(po_tmpl) );
1537 po_tmpl.insn = INSN_WRITE;
1539 po_tmpl.subdev = setup->da_subdev;
1541 setup->n_observables = 0;
1543 for(i = 0; i < num_ao_channels; i++)
1545 o = setup->observables + ni67xx_ao_ground_observable_index( setup,
1547 o->reference_source = -1;
1548 assert( o->name == NULL );
1549 asprintf(&o->name, "dac%i ground, ground referenced", i);
1550 o->preobserve_insn = po_tmpl;
1551 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1552 o->preobserve_insn.data = o->preobserve_data;
1553 o->observe_insn = tmpl;
1554 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1555 ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0, slope);
1556 setup->n_observables++;
1558 o = setup->observables + ni67xx_ao_mid_observable_index( setup,
1560 o->reference_source = -1;
1561 assert( o->name == NULL );
1562 asprintf(&o->name, "dac%i mid, ground referenced", i);
1563 o->preobserve_insn = po_tmpl;
1564 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1565 o->preobserve_insn.data = o->preobserve_data;
1566 o->observe_insn = tmpl;
1567 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1568 ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0, slope);
1569 setup->n_observables++;
1571 o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0);
1572 o->reference_source = -1;
1573 assert( o->name == NULL );
1574 asprintf(&o->name, "dac%i high, ground referenced", i);
1575 o->preobserve_insn = po_tmpl;
1576 o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND );
1577 o->preobserve_insn.data = o->preobserve_data;
1578 o->observe_insn = tmpl;
1579 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1580 ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0, slope);
1581 setup->n_observables++;
1587 static int cal_ni_pci_6711(calibration_setup_t *setup)
1589 generic_layout_t layout;
1591 init_generic_layout( &layout );
1592 layout.dac_gain = ni67xx_ao_gain_caldac;
1593 layout.dac_linearity = ni67xx_ao_linearity_caldac;
1594 layout.dac_offset = ni67xx_ao_offset_caldac;
1595 layout.dac_high_observable = ni67xx_ao_high_observable_index;
1596 layout.dac_mid_observable = ni67xx_ao_mid_observable_index;
1597 layout.dac_ground_observable = ni67xx_ao_ground_observable_index;
1598 layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 );
1599 return generic_cal_ao(setup, &layout);