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_pci_6711(calibration_setup_t *setup);
76 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
78 static struct board_struct boards[]={
79 { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
80 { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
81 { "at-mio-16e-1", STATUS_SOME, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
82 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
83 { "at-mio-16e-10", STATUS_GUESS, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
84 { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
85 { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
86 { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
87 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
88 { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
89 { "DAQCard-6036E", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
90 { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
91 { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
92 { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
93 { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
94 { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
95 { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
96 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
97 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
98 { "pci-6031e", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
99 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
100 { "pci-6033e", STATUS_SOME, cal_ni_pci_6032e, ni_setup_observables, -1, -1 },
101 { "pci-6034e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
102 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
103 { "pci-6036e", STATUS_DONE, cal_ni_pci_6036e, ni_setup_observables, 0x1ab, 0x1ac },
104 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
105 { "pci-6071e", STATUS_DONE, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
106 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
107 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
108 { "pxi-6025e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
109 { "pxi-6030e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
110 { "pxi-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
111 { "pxi-6040e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
112 { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
113 { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
114 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
115 { "pci-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
116 { "pci-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
117 { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
118 { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
119 { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
120 { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
121 { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
122 { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
124 { "at-mio-64e-3", cal_ni_16e_1 },
127 #define n_boards (sizeof(boards)/sizeof(boards[0]))
129 static const int ni_num_observables = 20;
131 ni_zero_offset_low = 0,
134 ni_unip_zero_offset_low,
135 ni_unip_zero_offset_high,
136 ni_unip_reference_low,
143 ni_ao0_unip_zero_offset,
144 ni_ao0_unip_reference,
145 ni_ao0_unip_low_linearity,
146 ni_ao0_unip_mid_linearity,
147 ni_ao1_unip_zero_offset,
148 ni_ao1_unip_reference,
149 ni_ao1_unip_low_linearity,
150 ni_ao1_unip_mid_linearity,
152 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
154 if( channel ) return ni_ao1_zero_offset;
155 else return ni_ao0_zero_offset;
157 static inline unsigned int ni_ao_reference( unsigned int channel )
159 if( channel ) return ni_ao1_reference;
160 else return ni_ao0_reference;
162 static inline unsigned int ni_ao_mid_linearity( unsigned int channel )
164 if( channel ) return ni_ao1_linearity;
165 else return ni_ao0_linearity;
167 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
169 if( channel ) return ni_ao1_unip_zero_offset;
170 else return ni_ao0_unip_zero_offset;
172 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
174 if( channel ) return ni_ao1_unip_reference;
175 else return ni_ao0_unip_reference;
177 static inline unsigned int ni_ao_unip_low_linearity( unsigned int channel )
179 if( channel ) return ni_ao1_unip_low_linearity;
180 else return ni_ao0_unip_low_linearity;
182 static inline unsigned int ni_ao_unip_mid_linearity( unsigned int channel )
184 if( channel ) return ni_ao1_unip_mid_linearity;
185 else return ni_ao0_unip_mid_linearity;
188 static const int num_ao_observables_611x = 4;
189 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
190 unsigned int channel, unsigned int range ) {
191 assert( range == 0 );
194 static int ni_ao_reference_611x( const calibration_setup_t *setup,
195 unsigned int channel, unsigned int range ) {
196 assert( range == 0 );
197 return 2 * channel + 1;
199 static int ni_zero_offset_611x( const calibration_setup_t *setup,
200 unsigned int channel, unsigned int range ) {
201 return num_ao_observables_611x + 8 * range + 2 * channel;
203 static int ni_reference_611x( const calibration_setup_t *setup,
204 unsigned int channel, unsigned int range ) {
205 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
208 enum reference_sources {
213 REF_CALSRC_CALSRC = 4,
218 static inline unsigned int REF_DAC_GND( unsigned int channel )
220 if( channel ) return REF_DAC1_GND;
221 else return REF_DAC0_GND;
223 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
225 if( channel ) return REF_DAC1_CALSRC;
226 else return REF_DAC0_CALSRC;
229 static struct board_struct* ni_board( calibration_setup_t *setup )
231 return setup->private_data;
236 int adc_pregain_offset;
237 int adc_postgain_offset;
239 int adc_pregain_offset_fine;
240 int adc_postgain_offset_fine;
243 int adc_unip_offset_fine;
246 int dac_gain_fine[ 2 ];
247 int dac_linearity[ 2 ];
248 } ni_caldac_layout_t;
250 static int cal_ni_generic( calibration_setup_t *setup,
251 const ni_caldac_layout_t *layout );
253 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
257 layout->adc_pregain_offset = -1;
258 layout->adc_postgain_offset = -1;
259 layout->adc_gain = -1;
260 layout->adc_unip_offset = -1;
261 layout->adc_unip_offset_fine = -1;
262 layout->adc_pregain_offset_fine = -1;
263 layout->adc_postgain_offset_fine = -1;
264 layout->adc_gain_fine = -1;
265 for( i = 0; i < 2; i++ )
267 layout->dac_offset[ i ] = -1;
268 layout->dac_gain[ i ] = -1;
269 layout->dac_gain_fine[ i ] = -1;
270 layout->dac_linearity[ i ] = -1;
274 int ni_setup( calibration_setup_t *setup , const char *device_name )
278 retval = ni_setup_board( setup, device_name );
279 if( retval < 0 ) return retval;
280 setup_caldacs( setup, setup->caldac_subdev );
285 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
289 for(i = 0; i < n_boards; i++ ){
290 if(!strcmp( device_name, boards[i].name )){
291 setup->status = boards[i].status;
292 setup->do_cal = boards[i].cal;
293 setup->private_data = &boards[ i ];
294 boards[i].setup_observables( setup );
298 if( i == n_boards ) return -1;
302 static void ni_setup_ao_observables( calibration_setup_t *setup )
305 comedi_insn tmpl, po_tmpl;
306 unsigned int channel;
307 int ai_bipolar_lowgain;
308 int ao_bipolar_lowgain;
309 int ao_unipolar_lowgain;
311 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
312 assert(ai_bipolar_lowgain >= 0);
313 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
314 assert(ao_bipolar_lowgain >= 0);
315 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
317 memset(&tmpl,0,sizeof(tmpl));
318 tmpl.insn = INSN_READ;
320 tmpl.subdev = setup->ad_subdev;
322 memset(&po_tmpl, 0, sizeof(po_tmpl));
323 po_tmpl.insn = INSN_WRITE;
325 po_tmpl.subdev = setup->da_subdev;
327 for( channel = 0; channel < 2; channel++ )
330 o = setup->observables + ni_ao_zero_offset( channel );
331 assert( o->name == NULL );
332 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
333 o->preobserve_insn = po_tmpl;
334 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
335 o->preobserve_insn.data = o->preobserve_data;
336 o->observe_insn = tmpl;
337 o->observe_insn.chanspec =
338 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
339 | CR_ALT_SOURCE | CR_ALT_FILTER;
340 o->reference_source = REF_DAC_GND( channel );
341 set_target( setup, ni_ao_zero_offset( channel ),0.0);
344 o = setup->observables + ni_ao_reference( channel );
345 assert( o->name == NULL );
346 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
347 o->preobserve_insn = po_tmpl;
348 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
349 o->preobserve_insn.data = o->preobserve_data;
350 o->observe_insn = tmpl;
351 o->observe_insn.chanspec =
352 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
353 | CR_ALT_SOURCE | CR_ALT_FILTER;
354 o->reference_source = REF_DAC_GND( channel );
355 set_target( setup, ni_ao_reference( channel ),8.0);
357 /* ao linearity, mid */
358 o = setup->observables + ni_ao_mid_linearity( channel );
359 assert( o->name == NULL );
360 asprintf( &o->name, "ao %i, linearity (mid), low gain", channel );
361 o->preobserve_insn = po_tmpl;
362 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
363 o->preobserve_insn.data = o->preobserve_data;
364 o->observe_insn = tmpl;
365 o->observe_insn.chanspec =
366 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
367 | CR_ALT_SOURCE | CR_ALT_FILTER;
368 o->reference_source = REF_DAC_GND( channel );
369 set_target( setup, ni_ao_mid_linearity( channel ),4.0);
371 if( ao_unipolar_lowgain >= 0 )
373 /* ao unipolar zero offset */
374 o = setup->observables + ni_ao_unip_zero_offset( channel );
375 assert( o->name == NULL );
376 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
377 o->preobserve_insn = po_tmpl;
378 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
379 o->preobserve_insn.data = o->preobserve_data;
380 o->observe_insn = tmpl;
381 o->observe_insn.chanspec =
382 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
383 | CR_ALT_SOURCE | CR_ALT_FILTER;
384 o->reference_source = REF_DAC_GND( channel );
385 set_target( setup, ni_ao_unip_zero_offset( channel ),0.0);
387 /* ao unipolar gain */
388 o = setup->observables + ni_ao_unip_reference( channel );
389 assert( o->name == NULL );
390 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
391 o->preobserve_insn = po_tmpl;
392 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
393 o->preobserve_insn.data = o->preobserve_data;
394 o->observe_insn = tmpl;
395 o->observe_insn.chanspec =
396 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
397 | CR_ALT_SOURCE | CR_ALT_FILTER;
398 o->reference_source = REF_DAC_GND( channel );
399 set_target( setup, ni_ao_unip_reference( channel ), 9.0);
401 /* ao unipolar linearity, mid */
402 o = setup->observables + ni_ao_unip_mid_linearity( channel );
403 assert( o->name == NULL );
404 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
405 o->preobserve_insn = po_tmpl;
406 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
407 o->preobserve_insn.data = o->preobserve_data;
408 o->observe_insn = tmpl;
409 o->observe_insn.chanspec =
410 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
411 | CR_ALT_SOURCE | CR_ALT_FILTER;
412 o->reference_source = REF_DAC_GND( channel );
413 set_target( setup, ni_ao_unip_mid_linearity( channel ), 5.0);
415 /* ao unipolar linearity, low */
416 o = setup->observables + ni_ao_unip_low_linearity( channel );
417 assert( o->name == NULL );
418 asprintf( &o->name, "ao %i, unipolar linearity (low), low gain", channel );
419 o->preobserve_insn = po_tmpl;
420 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
421 o->preobserve_insn.data = o->preobserve_data;
422 o->observe_insn = tmpl;
423 o->observe_insn.chanspec =
424 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
425 | CR_ALT_SOURCE | CR_ALT_FILTER;
426 o->reference_source = REF_DAC_GND( channel );
427 set_target( setup, ni_ao_unip_low_linearity( channel ), 1.0);
432 static void ni_setup_observables( calibration_setup_t *setup )
436 int bipolar_highgain;
437 int unipolar_lowgain;
438 int unipolar_highgain;
439 double voltage_reference;
442 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
443 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
444 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
445 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
447 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
448 ni_board( setup )->ref_eeprom_msb >= 0 )
450 voltage_reference = ni_get_reference( setup,
451 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
454 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
455 "correction. This might be fixable if you send us an eeprom dump\n"
456 "(see the demo/eeprom_dump program).\n");
457 voltage_reference = 5.0;
460 memset(&tmpl,0,sizeof(tmpl));
461 tmpl.insn = INSN_READ;
463 tmpl.subdev = setup->ad_subdev;
465 setup->n_observables = ni_num_observables;
467 /* 0 offset, low gain */
468 o = setup->observables + ni_zero_offset_low;
469 o->name = "ai, bipolar zero offset, low gain";
470 o->observe_insn = tmpl;
471 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
472 | CR_ALT_SOURCE | CR_ALT_FILTER;
473 o->reference_source = REF_GND_GND;
476 /* 0 offset, high gain */
477 o = setup->observables + ni_zero_offset_high;
478 o->name = "ai, bipolar zero offset, high gain";
479 o->observe_insn = tmpl;
480 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
481 | CR_ALT_SOURCE | CR_ALT_FILTER;
482 o->reference_source = REF_GND_GND;
485 /* voltage reference */
486 o = setup->observables + ni_reference_low;
487 o->name = "ai, bipolar voltage reference, low gain";
488 o->observe_insn = tmpl;
489 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
490 | CR_ALT_SOURCE | CR_ALT_FILTER;
491 o->reference_source = REF_CALSRC_GND;
492 o->target = voltage_reference;
494 if(unipolar_lowgain>=0){
495 o = setup->observables + ni_unip_zero_offset_low;
496 o->name = "ai, unipolar zero offset, low gain";
497 o->observe_insn = tmpl;
498 o->observe_insn.chanspec =
499 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
500 | CR_ALT_SOURCE | CR_ALT_FILTER;
501 o->reference_source = REF_GND_GND;
502 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
504 o = setup->observables + ni_unip_reference_low;
505 o->name = "ai, unipolar voltage reference, low gain";
506 o->observe_insn = tmpl;
507 o->observe_insn.chanspec =
508 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
509 | CR_ALT_SOURCE | CR_ALT_FILTER;
510 o->reference_source = REF_CALSRC_GND;
511 o->target = voltage_reference;
514 if(unipolar_highgain >= 0)
516 o = setup->observables + ni_unip_zero_offset_high;
517 o->name = "ai, unipolar zero offset, high gain";
518 o->observe_insn = tmpl;
519 o->observe_insn.chanspec =
520 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
521 | CR_ALT_SOURCE | CR_ALT_FILTER;
522 o->reference_source = REF_GND_GND;
523 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
526 if(setup->da_subdev >= 0)
527 ni_setup_ao_observables( setup );
530 /* for +-50V and +-20V ranges, the reference source goes 0V
531 * to 50V instead of 0V to 5V */
532 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
536 bits = 200.0 * ( *voltage / reference );
537 if( bits > 200 ) bits = 200;
538 if( bits < 0 ) bits = 0;
540 *voltage = reference * ( bits / 200.0 );
544 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
546 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
549 static void reference_target_611x( calibration_setup_t *setup,
550 observable *o, double master_reference, unsigned int range )
552 int cal_gain_reg_bits;
555 comedi_range *range_ptr;
557 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
558 assert( range_ptr != NULL );
559 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
560 else reference = master_reference;
561 target = range_ptr->max * 0.8;
563 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
565 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
569 static void ni_setup_observables_611x( calibration_setup_t *setup )
574 double master_reference;
576 int num_ai_channels, num_ai_ranges;
577 static const int num_ao_channels = 2;
579 setup->sv_settling_time_ns = 10000000;
580 setup->sv_order = 14;
582 master_reference = ni_get_reference( setup,
583 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
585 memset(&tmpl,0,sizeof(tmpl));
586 tmpl.insn = INSN_READ;
588 tmpl.subdev = setup->ad_subdev;
590 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
591 assert( num_ai_channels >= 0 );
592 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
593 assert( num_ai_ranges >= 0 );
595 for( channel = 0; channel < num_ai_channels; channel++ )
597 for( range = 0; range < num_ai_ranges; range++ )
600 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
601 assert( o->name == NULL );
602 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
604 o->observe_insn = tmpl;
605 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
606 | CR_ALT_SOURCE | CR_ALT_FILTER;
607 o->reference_source = REF_GND_GND;
610 /* voltage reference */
611 o = setup->observables + ni_reference_611x( setup, channel, range );
612 assert( o->name == NULL );
613 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
615 o->observe_insn = tmpl;
616 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
617 | CR_ALT_SOURCE | CR_ALT_FILTER;
618 reference_target_611x( setup, o, master_reference, range );
622 memset(&po_tmpl,0,sizeof(po_tmpl));
623 po_tmpl.insn = INSN_WRITE;
625 po_tmpl.subdev = setup->da_subdev;
627 for( channel = 0; channel < num_ao_channels; channel ++ )
629 static const int ai_range_for_ao = 2;
632 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
633 assert( o->name == NULL );
634 asprintf( &o->name, "ao ch %i, zero offset", channel );
635 o->preobserve_insn = po_tmpl;
636 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
637 o->preobserve_insn.data = o->preobserve_data;
638 o->observe_insn = tmpl;
639 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
640 | CR_ALT_SOURCE | CR_ALT_FILTER;
641 o->reference_source = REF_DAC_GND( channel );
642 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
645 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
646 assert( o->name == NULL );
647 asprintf( &o->name, "ao ch %i, reference voltage", channel );
648 o->preobserve_insn = po_tmpl;
649 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
650 o->preobserve_insn.data = o->preobserve_data;
651 o->observe_insn = tmpl;
652 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
653 | CR_ALT_SOURCE | CR_ALT_FILTER;
654 o->reference_source = REF_DAC_GND( channel );
655 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
658 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
661 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
663 ni_caldac_layout_t layout;
665 init_ni_caldac_layout( &layout );
666 layout.adc_pregain_offset = 0;
667 layout.adc_postgain_offset = 1;
669 layout.adc_unip_offset = 2;
670 layout.dac_offset[ 0 ] = 5;
671 layout.dac_gain[ 0 ] = 6;
672 layout.dac_offset[ 1 ] = 8;
673 layout.dac_gain[ 1 ] = 9;
675 return cal_ni_generic( setup, &layout );
678 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
680 ni_caldac_layout_t layout;
682 init_ni_caldac_layout( &layout );
683 layout.adc_pregain_offset = 8;
684 layout.adc_postgain_offset = 2;
686 layout.adc_gain_fine = 1;
688 return cal_ni_generic( setup, &layout );
691 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
693 ni_caldac_layout_t layout;
695 init_ni_caldac_layout( &layout );
696 layout.adc_pregain_offset = 8;
697 layout.adc_postgain_offset = 2;
699 layout.adc_gain_fine = 1;
700 layout.dac_offset[ 0 ] = 6;
701 layout.dac_gain[ 0 ] = 4;
702 layout.dac_offset[ 1 ] = 7;
703 layout.dac_gain[ 1 ] = 5;
705 return cal_ni_generic( setup, &layout );
708 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
710 ni_caldac_layout_t layout;
712 init_ni_caldac_layout( &layout );
713 layout.adc_pregain_offset = 8;
714 layout.adc_postgain_offset = 2;
715 layout.adc_postgain_offset_fine = 3;
717 layout.adc_gain_fine = 1;
718 layout.dac_offset[ 0 ] = 6;
719 layout.dac_gain[ 0 ] = 4;
720 layout.dac_offset[ 1 ] = 7;
721 layout.dac_gain[ 1 ] = 5;
723 return cal_ni_generic( setup, &layout );
726 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
728 return cal_ni_at_mio_16e_2( setup );
731 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
733 ni_caldac_layout_t layout;
735 init_ni_caldac_layout( &layout );
736 layout.adc_pregain_offset = 0;
737 layout.adc_postgain_offset = 1;
738 layout.adc_unip_offset = 2;
740 layout.dac_offset[ 0 ] = 5;
741 layout.dac_gain[ 0 ] = 6;
742 layout.dac_linearity[ 0 ] = 4;
743 layout.dac_offset[ 1 ] = 8;
744 layout.dac_gain[ 1 ] = 9;
745 layout.dac_linearity[ 1 ] = 7;
747 return cal_ni_generic( setup, &layout );
750 static int cal_ni_pci_6032e(calibration_setup_t *setup)
752 ni_caldac_layout_t layout;
754 init_ni_caldac_layout( &layout );
755 layout.adc_pregain_offset = 8;
756 layout.adc_postgain_offset = 2;
757 layout.adc_postgain_offset_fine = 3;
759 layout.adc_gain_fine = 1;
761 return cal_ni_generic( setup, &layout );
764 static int cal_ni_pci_6035e(calibration_setup_t *setup)
766 /* this is for the ad8804_debug caldac */
767 ni_caldac_layout_t layout;
769 init_ni_caldac_layout( &layout );
770 layout.adc_pregain_offset = 0;
771 layout.adc_pregain_offset_fine = 8;
772 layout.adc_postgain_offset = 4;
774 layout.dac_offset[ 0 ] = 6;
775 layout.dac_gain[ 0 ] = 11;
776 layout.dac_linearity[ 0 ] = 10;
777 layout.dac_offset[ 1 ] = 9;
778 layout.dac_gain[ 1 ] = 5;
779 layout.dac_linearity[ 1 ] = 1;
781 return cal_ni_generic( setup, &layout );
784 static int cal_ni_pci_6036e(calibration_setup_t *setup)
786 ni_caldac_layout_t layout;
788 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
790 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
791 "for this calibration to work properly\n" );
794 /* this is for the ad8804_debug caldac */
795 init_ni_caldac_layout( &layout );
796 layout.adc_pregain_offset = 0;
797 layout.adc_postgain_offset = 4;
798 layout.adc_pregain_offset_fine = 8;
800 layout.dac_offset[ 0 ] = 6;
801 layout.dac_gain[ 0 ] = 7;
802 layout.dac_gain_fine[ 0 ] = 11;
803 layout.dac_linearity[ 0 ] = 10;
804 layout.dac_offset[ 1 ] = 9;
805 layout.dac_gain[ 1 ] = 3;
806 layout.dac_gain_fine[ 1 ] = 5;
807 layout.dac_linearity[ 1 ] = 1;
809 return cal_ni_generic( setup, &layout );
812 static int cal_ni_pci_6071e(calibration_setup_t *setup)
814 ni_caldac_layout_t layout;
816 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
818 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
819 "for this calibration to work properly\n" );
822 init_ni_caldac_layout( &layout );
823 layout.adc_pregain_offset = 8;
824 layout.adc_postgain_offset = 4;
825 layout.adc_unip_offset = 7;
827 layout.dac_offset[ 0 ] = 6;
828 layout.dac_gain[ 0 ] = 11;
829 layout.dac_linearity[ 0 ] = 10;
830 layout.dac_offset[ 1 ] = 9;
831 layout.dac_gain[ 1 ] = 5;
832 layout.dac_linearity[ 1 ] = 1;
833 return cal_ni_generic( setup, &layout );
836 static int cal_ni_pxi_6071e(calibration_setup_t *setup)
838 ni_caldac_layout_t layout;
840 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
842 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
843 "for this calibration to work properly\n" );
846 init_ni_caldac_layout( &layout );
847 layout.adc_pregain_offset = 0;
848 layout.adc_pregain_offset_fine = 8;
849 layout.adc_postgain_offset = 4;
851 layout.dac_offset[ 0 ] = 6;
852 layout.dac_gain[ 0 ] = 11;
853 layout.dac_linearity[ 0 ] = 10;
854 layout.dac_offset[ 1 ] = 9;
855 layout.dac_gain[ 1 ] = 5;
856 layout.dac_linearity[ 1 ] = 1;
857 return cal_ni_generic( setup, &layout );
860 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
863 ni_caldac_layout_t layout;
865 init_ni_caldac_layout( &layout );
866 layout.adc_pregain_offset = 10;
867 layout.adc_pregain_offset_fine = 0;
868 layout.adc_postgain_offset = 1;
870 layout.adc_unip_offset = 2;
871 layout.dac_offset[ 0 ] = 5; /* guess */
872 layout.dac_gain[ 0 ] = 6; /* guess */
873 layout.dac_offset[ 1 ] = 8; /* guess */
874 layout.dac_gain[ 1 ] = 9; /* guess */
876 return cal_ni_generic( setup, &layout );
879 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
881 ni_caldac_layout_t layout;
883 init_ni_caldac_layout( &layout );
884 layout.adc_pregain_offset = 8;
885 layout.adc_postgain_offset = 2;
887 layout.adc_gain_fine = 1;
888 layout.adc_unip_offset = 7;
889 layout.dac_offset[ 0 ] = 6;
890 layout.dac_gain[ 0 ] = 4;
891 layout.dac_offset[ 1 ] = 7;
892 layout.dac_gain[ 1 ] = 5;
894 return cal_ni_generic( setup, &layout );
897 static int cal_ni_pci_6023e(calibration_setup_t *setup)
899 /* for comedi-0.7.65 */
900 ni_caldac_layout_t layout;
902 init_ni_caldac_layout( &layout );
903 layout.adc_pregain_offset = 8; /* possibly wrong */
904 layout.adc_pregain_offset_fine = 0;
905 layout.adc_postgain_offset = 4;
908 return cal_ni_generic( setup, &layout );
911 static int cal_ni_pci_6024e(calibration_setup_t *setup)
913 ni_caldac_layout_t layout;
915 init_ni_caldac_layout( &layout );
916 layout.adc_pregain_offset = 0;
917 layout.adc_postgain_offset = 4;
918 layout.adc_pregain_offset_fine = 8;
920 layout.dac_offset[ 0 ] = 6;
921 layout.dac_gain[ 0 ] = 11;
922 layout.dac_linearity[ 0 ] = 10;
923 layout.dac_offset[ 1 ] = 9;
924 layout.dac_gain[ 1 ] = 5;
925 layout.dac_linearity[ 1 ] = 1;
927 return cal_ni_generic( setup, &layout );
930 static int cal_ni_pci_6025e(calibration_setup_t *setup)
932 ni_caldac_layout_t layout;
934 init_ni_caldac_layout( &layout );
935 layout.adc_pregain_offset = 0;
936 layout.adc_postgain_offset = 4;
937 layout.adc_pregain_offset_fine = 8;
939 layout.dac_offset[ 0 ] = 6;
940 layout.dac_gain[ 0 ] = 11;
941 layout.dac_linearity[ 0 ] = 10;
942 layout.dac_offset[ 1 ] = 9;
943 layout.dac_gain[ 1 ] = 5;
944 layout.dac_linearity[ 1 ] = 1;
946 return cal_ni_generic( setup, &layout );
949 static int cal_ni_pci_6052e(calibration_setup_t *setup)
952 * This board has noisy caldacs
954 * The NI documentation says (true mb88341 addressing):
955 * 0, 8 AI pregain (coarse, fine)
958 * 14, 7 AI unipolar offset
964 * 10, 6 AO1 reference
967 * For us, these map to (ad8804 channels)
969 * 0, 1 AI pregain (coarse, fine)
972 * 7 AI unipolar offset
981 * or, with mb88341 channels
991 ni_caldac_layout_t layout;
993 init_ni_caldac_layout( &layout );
994 layout.adc_pregain_offset = 0;
995 layout.adc_postgain_offset = 2;
997 layout.adc_unip_offset = 6;
998 layout.adc_unip_offset_fine = 7;
999 layout.adc_pregain_offset_fine = 1;
1000 layout.adc_postgain_offset_fine = 3;
1001 layout.adc_gain_fine = 5;
1003 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1004 "for this calibration to work properly\n" );
1005 /* this works when the first two caldacs are ad8804_debug */
1006 layout.dac_offset[ 0 ] = 16 + 3;
1007 layout.dac_gain[ 0 ] = 16 + 1;
1008 layout.dac_gain_fine[ 0 ] = 16 + 2;
1009 layout.dac_linearity[ 0 ] = 16 + 0;
1010 layout.dac_offset[ 1 ] = 16 + 7;
1011 layout.dac_gain[ 1 ] = 16 + 5;
1012 layout.dac_gain_fine[ 1 ] = 16 + 6;
1013 layout.dac_linearity[ 1 ] = 16 + 4;
1015 return cal_ni_generic( setup, &layout );
1018 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
1020 ni_caldac_layout_t layout;
1022 init_ni_caldac_layout( &layout );
1023 layout.adc_pregain_offset = 0;
1024 layout.adc_postgain_offset = 1;
1025 layout.adc_gain = 3;
1026 layout.adc_unip_offset = 2;
1028 return cal_ni_generic( setup, &layout );
1031 static int adc_offset_611x( unsigned int channel )
1033 return 2 * channel + 2;
1035 static int adc_gain_611x( unsigned int channel )
1037 return 2 * channel + 1;
1039 static int dac_offset_611x( unsigned int channel )
1041 return 12 + 2 + 2 * channel;
1043 static int dac_gain_611x( unsigned int channel )
1045 return 12 + 1 + 2 * channel;
1047 static int cal_ni_pci_611x( calibration_setup_t *setup )
1049 generic_layout_t layout;
1051 init_generic_layout( &layout );
1052 layout.adc_offset = adc_offset_611x;
1053 layout.adc_gain = adc_gain_611x;
1054 layout.dac_offset = dac_offset_611x;
1055 layout.dac_gain = dac_gain_611x;
1056 layout.adc_high_observable = ni_reference_611x;
1057 layout.adc_ground_observable = ni_zero_offset_611x;
1058 layout.dac_high_observable = ni_ao_reference_611x;
1059 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1061 return generic_cal_by_channel_and_range( setup, &layout );
1064 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1066 ni_caldac_layout_t layout;
1068 init_ni_caldac_layout( &layout );
1069 layout.adc_pregain_offset = 8;
1070 layout.adc_postgain_offset = 4;
1071 layout.adc_gain = 2;
1072 layout.adc_unip_offset = 7;
1073 layout.dac_offset[ 0 ] = 6;
1074 layout.dac_gain[ 0 ] = 11;
1075 layout.dac_linearity[ 0 ] = 10;
1076 layout.dac_offset[ 1 ] = 9;
1077 layout.dac_gain[ 1 ] = 5;
1078 layout.dac_linearity[ 1 ] = 1;
1080 return cal_ni_generic( setup, &layout );
1083 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1085 ni_caldac_layout_t layout;
1087 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1089 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1090 "for this calibration to work properly\n" );
1092 init_ni_caldac_layout( &layout );
1093 layout.adc_pregain_offset = 8;
1094 layout.adc_postgain_offset = 4;
1095 layout.adc_gain = 2;
1096 layout.adc_unip_offset = 7;
1097 layout.dac_offset[ 0 ] = 6;
1098 layout.dac_gain[ 0 ] = 11;
1099 layout.dac_linearity[ 0 ] = 10;
1100 layout.dac_offset[ 1 ] = 9;
1101 layout.dac_gain[ 1 ] = 5;
1102 layout.dac_linearity[ 1 ] = 1;
1104 return cal_ni_generic( setup, &layout );
1107 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1109 ni_caldac_layout_t layout;
1111 init_ni_caldac_layout( &layout );
1113 layout.adc_pregain_offset = 0;
1114 layout.adc_postgain_offset = 4;
1115 layout.adc_gain = 2;
1116 //layout.adc_unip_offset = 7;
1117 layout.dac_offset[ 0 ] = 6;
1118 layout.dac_gain[ 0 ] = 3;
1119 //layout.dac_linearity[ 0 ] = 10;
1120 layout.dac_offset[ 1 ] = 1;
1121 layout.dac_gain[ 1 ] = 5;
1122 //layout.dac_linearity[ 1 ] = 1;
1124 return cal_ni_generic( setup, &layout );
1127 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1128 const ni_caldac_layout_t *layout, unsigned int range )
1132 if( setup->old_calibration == NULL )
1134 reset_caldac( setup, layout->adc_pregain_offset );
1135 reset_caldac( setup, layout->adc_postgain_offset );
1136 reset_caldac( setup, layout->adc_gain );
1137 reset_caldac( setup, layout->adc_pregain_offset_fine );
1138 reset_caldac( setup, layout->adc_postgain_offset_fine );
1139 reset_caldac( setup, layout->adc_gain_fine );
1140 reset_caldac( setup, layout->adc_unip_offset );
1141 reset_caldac( setup, layout->adc_unip_offset_fine );
1144 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1145 0, range, AREF_GROUND, setup->old_calibration );
1148 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1149 reset_caldac( setup, layout->adc_pregain_offset );
1150 reset_caldac( setup, layout->adc_postgain_offset );
1151 reset_caldac( setup, layout->adc_gain );
1152 reset_caldac( setup, layout->adc_pregain_offset_fine );
1153 reset_caldac( setup, layout->adc_postgain_offset_fine );
1154 reset_caldac( setup, layout->adc_gain_fine );
1155 reset_caldac( setup, layout->adc_unip_offset );
1156 reset_caldac( setup, layout->adc_unip_offset_fine );
1161 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1162 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1166 if( setup->da_subdev < 0 ) return;
1168 if( setup->old_calibration == NULL )
1170 reset_caldac( setup, layout->dac_offset[ channel ] );
1171 reset_caldac( setup, layout->dac_gain[ channel ] );
1172 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1173 reset_caldac( setup, layout->dac_linearity[ channel ] );
1176 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1177 channel, range, AREF_GROUND, setup->old_calibration );
1180 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1181 reset_caldac( setup, layout->dac_offset[ channel ] );
1182 reset_caldac( setup, layout->dac_gain[ channel ] );
1183 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1184 reset_caldac( setup, layout->dac_linearity[ channel ] );
1189 static void prep_adc_for_dac( calibration_setup_t *setup, int observable )
1191 unsigned int adc_range;
1194 if( observable < 0 ) return;
1196 chanspec = setup->observables[ observable ].observe_insn.chanspec;
1197 adc_range = CR_RANGE( chanspec );
1199 comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1200 0, adc_range, 0, setup->new_calibration );
1203 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1205 comedi_calibration_setting_t *current_cal;
1209 int ai_unipolar_lowgain, ai_bipolar_lowgain;
1211 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
1212 assert( num_ai_ranges > 0 );
1214 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
1215 ai_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev );
1217 prep_adc_caldacs_generic( setup, layout, ai_bipolar_lowgain );
1219 current_cal = sc_alloc_calibration_setting( setup );
1220 current_cal->subdevice = setup->ad_subdev;
1221 reset_caldac( setup, layout->adc_gain_fine );
1222 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1223 ni_reference_low, layout->adc_gain );
1224 reset_caldac( setup, layout->adc_postgain_offset_fine );
1225 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1226 ni_zero_offset_high, layout->adc_postgain_offset );
1227 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1228 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1229 reset_caldac( setup, layout->adc_pregain_offset_fine );
1230 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1231 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1232 ni_reference_low, layout->adc_gain_fine );
1233 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1234 layout->adc_pregain_offset_fine );
1235 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1236 sc_push_aref( current_cal, SC_ALL_AREFS );
1237 if( layout->adc_unip_offset >= 0 )
1239 sc_push_range( current_cal, SC_ALL_RANGES );
1242 for( range = 0; range < num_ai_ranges; range++ )
1244 if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
1245 sc_push_range( current_cal, range );
1249 /* do seperate unipolar calibration if appropriate */
1250 if( ai_unipolar_lowgain >= 0 )
1252 current_cal = sc_alloc_calibration_setting( setup );
1253 current_cal->subdevice = setup->ad_subdev;
1254 if( layout->adc_unip_offset >= 0 )
1256 reset_caldac( setup, layout->adc_unip_offset_fine );
1257 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1258 layout->adc_unip_offset );
1259 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1260 layout->adc_unip_offset_fine );
1263 prep_adc_caldacs_generic( setup, layout, ai_unipolar_lowgain );
1264 generic_peg( setup, ni_unip_zero_offset_low,
1265 layout->adc_pregain_offset, 1 );
1266 reset_caldac( setup, layout->adc_gain_fine );
1267 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1268 ni_unip_reference_low, layout->adc_gain );
1269 reset_caldac( setup, layout->adc_postgain_offset_fine );
1270 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1271 ni_unip_zero_offset_high, layout->adc_postgain_offset );
1272 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1273 ni_unip_zero_offset_high, layout->adc_postgain_offset_fine );
1274 reset_caldac( setup, layout->adc_pregain_offset_fine );
1275 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1276 layout->adc_pregain_offset );
1277 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1278 ni_unip_reference_low, layout->adc_gain_fine );
1279 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1280 layout->adc_pregain_offset_fine );
1282 for( range = 0; range < num_ai_ranges; range++ )
1284 if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
1285 sc_push_range( current_cal, range );
1287 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1288 sc_push_aref( current_cal, SC_ALL_AREFS );
1290 if( setup->da_subdev >= 0 && setup->do_output )
1292 unsigned int channel, range;
1293 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1294 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1297 for( channel = 0; channel < 2; channel++ )
1299 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1300 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1301 prep_adc_for_dac( setup, ni_ao_reference( channel ) );
1303 current_cal = sc_alloc_calibration_setting( setup );
1304 current_cal->subdevice = setup->da_subdev;
1305 generic_do_linearity( setup, current_cal, ni_ao_zero_offset( channel ),
1306 ni_ao_mid_linearity( channel ), ni_ao_reference( channel ),
1307 layout->dac_linearity[ channel ] );
1308 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1309 layout->dac_offset[ channel ] );
1310 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1311 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1312 layout->dac_gain[ channel ] );
1313 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1314 layout->dac_gain_fine[ channel ] );
1315 sc_push_channel( current_cal, channel );
1316 for( range = 0; range < num_ao_ranges; range++ )
1318 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1319 sc_push_range( current_cal, range );
1321 sc_push_aref( current_cal, SC_ALL_AREFS );
1323 if( ao_unipolar_lowgain >= 0 )
1325 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1327 current_cal = sc_alloc_calibration_setting( setup );
1328 current_cal->subdevice = setup->da_subdev;
1329 generic_do_linearity( setup, current_cal, ni_ao_unip_low_linearity( channel ),
1330 ni_ao_unip_mid_linearity( channel ), ni_ao_unip_reference( channel ),
1331 layout->dac_linearity[ channel ] );
1332 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1333 layout->dac_offset[ channel ] );
1334 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1335 layout->dac_gain[ channel ] );
1336 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1337 layout->dac_gain_fine[ channel ] );
1338 sc_push_channel( current_cal, channel );
1339 for( range = 0; range < num_ao_ranges; range++ )
1341 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1342 sc_push_range( current_cal, range );
1344 sc_push_aref( current_cal, SC_ALL_AREFS );
1349 retval = write_calibration_file( setup );
1354 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1360 lsb=read_eeprom( setup, lsb_loc );
1361 msb=read_eeprom( setup, msb_loc );
1362 assert( lsb >=0 && msb >= 0 );
1363 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1365 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1366 ref=5.000+1.0e-6*uv;
1367 DPRINT(0, "resulting reference voltage: %g\n", ref );
1368 if( fabs( ref - 5.0 ) > 0.005 )
1369 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1370 "from 5V. Possible bad eeprom address?\n" );
1376 NI 671x and 673x support
1379 static const int channels_per_ad8804 = 16;
1381 static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel)
1383 int ad8804_gain_channels[4] = {8, 2, 11, 5};
1384 int caldac_channel = ad8804_gain_channels[ao_channel % 4];
1385 int caldac_index = ao_channel / 4;
1386 /* just guessing that second ad8804 is works for ao channels 4-7
1387 * the same as the first ad8804 works for ao channels 0-3 */
1388 return caldac_index * channels_per_ad8804 + caldac_channel;
1390 static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel)
1392 int ad8804_linearity_channels[4] = {4, 10, 1, 0};
1393 int caldac_channel = ad8804_linearity_channels[ao_channel % 4];
1394 int caldac_index = ao_channel / 4;
1396 return caldac_index * channels_per_ad8804 + caldac_channel;
1398 static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel)
1400 int ad8804_offset_channels[4] = {7, 6, 9, 3};
1401 int caldac_channel = ad8804_offset_channels[ao_channel % 4];
1402 int caldac_index = ao_channel / 4;
1404 return caldac_index * channels_per_ad8804 + caldac_channel;
1407 static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup,
1408 unsigned int channel, unsigned int ao_range )
1413 static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup,
1414 unsigned int channel, unsigned int ao_range )
1416 return 3 * channel + 1;
1419 static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup,
1420 unsigned int channel, unsigned int ao_range )
1422 return 3 * channel + 2;
1425 /* calibration adc uses RANGE_UNKNOWN, so it will return a value from
1426 0.0 to 1.0 instead of a voltage, so we need to renormalize. */
1427 void ni67xx_set_target( calibration_setup_t *setup, int obs,double target)
1429 static const double reference = 5.0;
1431 set_target(setup, obs, target);
1432 /* calibration adc is roughly +=10V range, and inverted */
1433 setup->observables[obs].target *= -1.0 / (reference * 4.0);
1434 setup->observables[obs].target += 0.5;
1437 static void ni67xx_setup_observables( calibration_setup_t *setup )
1439 comedi_insn tmpl, po_tmpl;
1441 int num_ao_channels;
1444 /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */
1445 setup->sv_order = 1;
1447 num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev);
1448 assert(num_ao_channels >= 0);
1450 memset( &tmpl, 0, sizeof(tmpl) );
1451 tmpl.insn = INSN_READ;
1453 tmpl.subdev = setup->ad_subdev;
1455 memset( &po_tmpl, 0, sizeof(po_tmpl) );
1456 po_tmpl.insn = INSN_WRITE;
1458 po_tmpl.subdev = setup->da_subdev;
1460 setup->n_observables = 0;
1462 for(i = 0; i < num_ao_channels; i++)
1464 o = setup->observables + ni67xx_ao_ground_observable_index( setup,
1466 o->reference_source = -1;
1467 assert( o->name == NULL );
1468 asprintf(&o->name, "dac%i ground, ground referenced", i);
1469 o->preobserve_insn = po_tmpl;
1470 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1471 o->preobserve_insn.data = o->preobserve_data;
1472 o->observe_insn = tmpl;
1473 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1474 ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0);
1475 setup->n_observables++;
1477 o = setup->observables + ni67xx_ao_mid_observable_index( setup,
1479 o->reference_source = -1;
1480 assert( o->name == NULL );
1481 asprintf(&o->name, "dac%i mid, ground referenced", i);
1482 o->preobserve_insn = po_tmpl;
1483 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1484 o->preobserve_insn.data = o->preobserve_data;
1485 o->observe_insn = tmpl;
1486 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1487 ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0);
1488 setup->n_observables++;
1490 o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0);
1491 o->reference_source = -1;
1492 assert( o->name == NULL );
1493 asprintf(&o->name, "dac%i high, ground referenced", i);
1494 o->preobserve_insn = po_tmpl;
1495 o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND );
1496 o->preobserve_insn.data = o->preobserve_data;
1497 o->observe_insn = tmpl;
1498 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1499 ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0);
1500 setup->n_observables++;
1506 static int cal_ni_pci_6711(calibration_setup_t *setup)
1508 generic_layout_t layout;
1510 init_generic_layout( &layout );
1511 layout.dac_gain = ni67xx_ao_gain_caldac;
1512 layout.dac_linearity = ni67xx_ao_linearity_caldac;
1513 layout.dac_offset = ni67xx_ao_offset_caldac;
1514 layout.dac_high_observable = ni67xx_ao_high_observable_index;
1515 layout.dac_mid_observable = ni67xx_ao_mid_observable_index;
1516 layout.dac_ground_observable = ni67xx_ao_ground_observable_index;
1517 layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 );
1518 return generic_cal_ao(setup, &layout);