2 A little auto-calibration utility, for boards
5 copyright (C) 1999,2000,2001,2002 by David Schleef
6 copyright (C) 2003 by Frank Mori Hess
10 /***************************************************************************
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU Lesser General Public License as *
15 * the Free Software Foundation; either version 2.1 of the License, or *
16 * (at your option) any later version. *
18 ***************************************************************************/
36 char ni_id[] = "$Id$";
41 int (*cal)( calibration_setup_t *setup);
42 void (*setup_observables)( calibration_setup_t *setup );
47 static int ni_setup_board( calibration_setup_t *setup , const char *device_name );
48 static void ni_setup_observables( calibration_setup_t *setup );
49 static void ni_setup_observables_611x( calibration_setup_t *setup );
50 static void ni67xx_setup_observables( calibration_setup_t *setup );
52 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup);
53 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup);
54 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup);
55 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup);
56 static int cal_ni_pci_6014(calibration_setup_t *setup);
57 static int cal_ni_pci_6024e(calibration_setup_t *setup);
58 static int cal_ni_pci_6025e(calibration_setup_t *setup);
59 static int cal_ni_pci_6032e(calibration_setup_t *setup);
60 static int cal_ni_pci_6035e(calibration_setup_t *setup);
61 static int cal_ni_pci_6036e(calibration_setup_t *setup);
62 static int cal_ni_pci_6071e(calibration_setup_t *setup);
63 static int cal_ni_pxi_6071e(calibration_setup_t *setup);
64 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup);
65 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup);
66 static int cal_ni_pci_6023e(calibration_setup_t *setup);
67 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup);
68 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup);
69 static int cal_ni_pci_6052e(calibration_setup_t *setup);
70 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup);
71 static int cal_ni_pci_611x(calibration_setup_t *setup);
72 static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup);
73 static int cal_ni_daqcard_6062e(calibration_setup_t *setup);
74 static int cal_ni_daqcard_6024e(calibration_setup_t *setup);
75 static int cal_ni_daqcard_6036e(calibration_setup_t *setup);
76 static int cal_ni_pci_6711(calibration_setup_t *setup);
78 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc);
80 static struct board_struct boards[]={
81 { "at-ai-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
82 { "at-mio-16de-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1a7, 0x1a8 },
83 { "at-mio-16e-1", STATUS_DONE, cal_ni_at_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
84 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, 0x1a9, 0x1aa },
85 { "at-mio-16e-10", STATUS_DONE, cal_ni_at_mio_16e_10, ni_setup_observables, 0x1a7, 0x1a8 },
86 { "at-mio-16xe-10", STATUS_UNKNOWN, NULL, ni_setup_observables, 0x1b7, 0x1b8 },
87 { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
88 { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, 0x1b5, 0x1b6 },
89 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, 0x1be, 0x1bf },
90 { "DAQCard-6024E", STATUS_SOME, cal_ni_daqcard_6024e, ni_setup_observables, -1, -1 },
91 { "DAQCard-6036E", STATUS_DONE, cal_ni_daqcard_6036e, ni_setup_observables, 0x1ab, 0x1ac },
92 { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, 0x1a9, 0x1aa },
93 { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, 0x1a9, 0x1aa },
94 { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, 0x1a9, 0x1aa },
95 { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
96 { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, 0x1b5, 0x1b6 },
97 { "pci-6014", STATUS_SOME, cal_ni_pci_6014, ni_setup_observables, 0x1ab, 0x1ac },
98 { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, 0x1bb, 0x1bc },
99 { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, 0x1af, 0x1b0 },
100 { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, 0x1af, 0x1b0 },
101 { "pci-6031e", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, 0x1ae, 0x1af },
102 { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1ae, 0x1af },
103 { "pci-6033e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, 0x1b7, 0x1b8 },
104 { "pci-6034e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
105 { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, 0x1af, 0x1b0 },
106 { "pci-6036e", STATUS_DONE, cal_ni_pci_6036e, ni_setup_observables, 0x1ab, 0x1ac },
107 { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, 0x19f, 0x1a0 },
108 { "pci-6071e", STATUS_DONE, cal_ni_pci_6071e, ni_setup_observables, 0x1a9, 0x1aa },
109 { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
110 { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, 0x1d4, 0x1d5 },
111 { "pxi-6025e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
112 { "pxi-6030e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
113 { "pxi-6031e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
114 { "pxi-6040e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
115 { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
116 { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 },
117 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 },
118 { "pci-6711", STATUS_DONE, cal_ni_pci_6711, ni67xx_setup_observables, 0x1d4, 0x1d5},
119 { "pci-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, 0x1a9, 0x1aa},
120 { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
121 { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
122 { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
123 { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
124 { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
125 { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1},
127 { "at-mio-64e-3", cal_ni_16e_1 },
130 #define n_boards (sizeof(boards)/sizeof(boards[0]))
132 static const int ni_num_observables = 20;
134 ni_zero_offset_low = 0,
137 ni_unip_zero_offset_low,
138 ni_unip_zero_offset_high,
139 ni_unip_reference_low,
146 ni_ao0_unip_zero_offset,
147 ni_ao0_unip_reference,
148 ni_ao0_unip_low_linearity,
149 ni_ao0_unip_mid_linearity,
150 ni_ao1_unip_zero_offset,
151 ni_ao1_unip_reference,
152 ni_ao1_unip_low_linearity,
153 ni_ao1_unip_mid_linearity,
155 static inline unsigned int ni_ao_zero_offset( unsigned int channel )
157 if( channel ) return ni_ao1_zero_offset;
158 else return ni_ao0_zero_offset;
160 static inline unsigned int ni_ao_reference( unsigned int channel )
162 if( channel ) return ni_ao1_reference;
163 else return ni_ao0_reference;
165 static inline unsigned int ni_ao_mid_linearity( unsigned int channel )
167 if( channel ) return ni_ao1_linearity;
168 else return ni_ao0_linearity;
170 static inline unsigned int ni_ao_unip_zero_offset( unsigned int channel )
172 if( channel ) return ni_ao1_unip_zero_offset;
173 else return ni_ao0_unip_zero_offset;
175 static inline unsigned int ni_ao_unip_reference( unsigned int channel )
177 if( channel ) return ni_ao1_unip_reference;
178 else return ni_ao0_unip_reference;
180 static inline unsigned int ni_ao_unip_low_linearity( unsigned int channel )
182 if( channel ) return ni_ao1_unip_low_linearity;
183 else return ni_ao0_unip_low_linearity;
185 static inline unsigned int ni_ao_unip_mid_linearity( unsigned int channel )
187 if( channel ) return ni_ao1_unip_mid_linearity;
188 else return ni_ao0_unip_mid_linearity;
191 static const int num_ao_observables_611x = 4;
192 static int ni_ao_zero_offset_611x( const calibration_setup_t *setup,
193 unsigned int channel, unsigned int range ) {
194 assert( range == 0 );
197 static int ni_ao_reference_611x( const calibration_setup_t *setup,
198 unsigned int channel, unsigned int range ) {
199 assert( range == 0 );
200 return 2 * channel + 1;
202 static int ni_zero_offset_611x( const calibration_setup_t *setup,
203 unsigned int channel, unsigned int range ) {
204 return num_ao_observables_611x + 8 * range + 2 * channel;
206 static int ni_reference_611x( const calibration_setup_t *setup,
207 unsigned int channel, unsigned int range ) {
208 return num_ao_observables_611x + 8 * range + 2 * channel + 1;
211 enum reference_sources {
216 REF_CALSRC_CALSRC = 4,
221 static inline unsigned int REF_DAC_GND( unsigned int channel )
223 if( channel ) return REF_DAC1_GND;
224 else return REF_DAC0_GND;
226 static inline unsigned int REF_DAC_CALSRC( unsigned int channel )
228 if( channel ) return REF_DAC1_CALSRC;
229 else return REF_DAC0_CALSRC;
232 static struct board_struct* ni_board( calibration_setup_t *setup )
234 return setup->private_data;
239 int adc_pregain_offset;
240 int adc_postgain_offset;
242 int adc_pregain_offset_fine;
243 int adc_postgain_offset_fine;
246 int adc_unip_offset_fine;
248 int dac_offset_fine[ 2 ];
250 int dac_gain_fine[ 2 ];
251 int dac_linearity[ 2 ];
252 } ni_caldac_layout_t;
254 static int cal_ni_generic( calibration_setup_t *setup,
255 const ni_caldac_layout_t *layout );
257 static inline void init_ni_caldac_layout( ni_caldac_layout_t *layout )
261 layout->adc_pregain_offset = -1;
262 layout->adc_postgain_offset = -1;
263 layout->adc_gain = -1;
264 layout->adc_unip_offset = -1;
265 layout->adc_unip_offset_fine = -1;
266 layout->adc_pregain_offset_fine = -1;
267 layout->adc_postgain_offset_fine = -1;
268 layout->adc_gain_fine = -1;
269 for( i = 0; i < 2; i++ )
271 layout->dac_offset[ i ] = -1;
272 layout->dac_offset_fine[ i ] = -1;
273 layout->dac_gain[ i ] = -1;
274 layout->dac_gain_fine[ i ] = -1;
275 layout->dac_linearity[ i ] = -1;
279 int ni_setup( calibration_setup_t *setup , const char *device_name )
283 retval = ni_setup_board( setup, device_name );
284 if( retval < 0 ) return retval;
285 setup_caldacs( setup, setup->caldac_subdev );
290 static int ni_setup_board( calibration_setup_t *setup, const char *device_name )
294 for(i = 0; i < n_boards; i++ ){
295 if(!strcmp( device_name, boards[i].name )){
296 setup->status = boards[i].status;
297 setup->do_cal = boards[i].cal;
298 setup->private_data = &boards[ i ];
299 boards[i].setup_observables( setup );
303 if( i == n_boards ) return -1;
307 static void ni_setup_ao_observables( calibration_setup_t *setup )
310 comedi_insn tmpl, po_tmpl;
311 unsigned int channel;
312 int ai_bipolar_lowgain;
313 int ao_bipolar_lowgain;
314 int ao_unipolar_lowgain;
316 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
317 assert(ai_bipolar_lowgain >= 0);
318 ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev);
319 assert(ao_bipolar_lowgain >= 0);
320 ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev);
322 memset(&tmpl,0,sizeof(tmpl));
323 tmpl.insn = INSN_READ;
325 tmpl.subdev = setup->ad_subdev;
327 memset(&po_tmpl, 0, sizeof(po_tmpl));
328 po_tmpl.insn = INSN_WRITE;
330 po_tmpl.subdev = setup->da_subdev;
332 for( channel = 0; channel < 2; channel++ )
335 o = setup->observables + ni_ao_zero_offset( channel );
336 assert( o->name == NULL );
337 asprintf( &o->name, "ao %i, zero offset, low gain", channel );
338 o->preobserve_insn = po_tmpl;
339 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
340 o->preobserve_insn.data = o->preobserve_data;
341 o->observe_insn = tmpl;
342 o->observe_insn.chanspec =
343 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
344 | CR_ALT_SOURCE | CR_ALT_FILTER;
345 o->reference_source = REF_DAC_GND( channel );
346 set_target( setup, ni_ao_zero_offset( channel ),0.0);
349 o = setup->observables + ni_ao_reference( channel );
350 assert( o->name == NULL );
351 asprintf( &o->name, "ao %i, reference voltage, low gain", channel );
352 o->preobserve_insn = po_tmpl;
353 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
354 o->preobserve_insn.data = o->preobserve_data;
355 o->observe_insn = tmpl;
356 o->observe_insn.chanspec =
357 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
358 | CR_ALT_SOURCE | CR_ALT_FILTER;
359 o->reference_source = REF_DAC_GND( channel );
360 set_target( setup, ni_ao_reference( channel ),8.0);
362 /* ao linearity, mid */
363 o = setup->observables + ni_ao_mid_linearity( channel );
364 assert( o->name == NULL );
365 asprintf( &o->name, "ao %i, linearity (mid), low gain", channel );
366 o->preobserve_insn = po_tmpl;
367 o->preobserve_insn.chanspec = CR_PACK(channel,ao_bipolar_lowgain,0);
368 o->preobserve_insn.data = o->preobserve_data;
369 o->observe_insn = tmpl;
370 o->observe_insn.chanspec =
371 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
372 | CR_ALT_SOURCE | CR_ALT_FILTER;
373 o->reference_source = REF_DAC_GND( channel );
374 set_target( setup, ni_ao_mid_linearity( channel ),4.0);
376 if( ao_unipolar_lowgain >= 0 )
378 /* ao unipolar zero offset */
379 o = setup->observables + ni_ao_unip_zero_offset( channel );
380 assert( o->name == NULL );
381 asprintf( &o->name, "ao %i, unipolar zero offset, low gain", channel );
382 o->preobserve_insn = po_tmpl;
383 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
384 o->preobserve_insn.data = o->preobserve_data;
385 o->observe_insn = tmpl;
386 o->observe_insn.chanspec =
387 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
388 | CR_ALT_SOURCE | CR_ALT_FILTER;
389 o->reference_source = REF_DAC_GND( channel );
390 set_target( setup, ni_ao_unip_zero_offset( channel ),0.0);
392 /* ao unipolar gain */
393 o = setup->observables + ni_ao_unip_reference( channel );
394 assert( o->name == NULL );
395 asprintf( &o->name, "ao %i, unipolar high, low gain", channel );
396 o->preobserve_insn = po_tmpl;
397 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
398 o->preobserve_insn.data = o->preobserve_data;
399 o->observe_insn = tmpl;
400 o->observe_insn.chanspec =
401 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
402 | CR_ALT_SOURCE | CR_ALT_FILTER;
403 o->reference_source = REF_DAC_GND( channel );
404 set_target( setup, ni_ao_unip_reference( channel ), 9.0);
406 /* ao unipolar linearity, mid */
407 o = setup->observables + ni_ao_unip_mid_linearity( channel );
408 assert( o->name == NULL );
409 asprintf( &o->name, "ao %i, unipolar linearity (mid), low gain", channel );
410 o->preobserve_insn = po_tmpl;
411 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
412 o->preobserve_insn.data = o->preobserve_data;
413 o->observe_insn = tmpl;
414 o->observe_insn.chanspec =
415 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
416 | CR_ALT_SOURCE | CR_ALT_FILTER;
417 o->reference_source = REF_DAC_GND( channel );
418 set_target( setup, ni_ao_unip_mid_linearity( channel ), 5.0);
420 /* ao unipolar linearity, low */
421 o = setup->observables + ni_ao_unip_low_linearity( channel );
422 assert( o->name == NULL );
423 asprintf( &o->name, "ao %i, unipolar linearity (low), low gain", channel );
424 o->preobserve_insn = po_tmpl;
425 o->preobserve_insn.chanspec = CR_PACK(channel,ao_unipolar_lowgain,0);
426 o->preobserve_insn.data = o->preobserve_data;
427 o->observe_insn = tmpl;
428 o->observe_insn.chanspec =
429 CR_PACK(REF_DAC_GND( channel ),ai_bipolar_lowgain,AREF_OTHER)
430 | CR_ALT_SOURCE | CR_ALT_FILTER;
431 o->reference_source = REF_DAC_GND( channel );
432 set_target( setup, ni_ao_unip_low_linearity( channel ), 1.0);
437 static void ni_setup_observables( calibration_setup_t *setup )
441 int bipolar_highgain;
442 int unipolar_lowgain;
443 int unipolar_highgain;
444 double voltage_reference;
447 bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev);
448 bipolar_highgain = get_bipolar_highgain( setup->dev, setup->ad_subdev);
449 unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev);
450 unipolar_highgain = get_unipolar_highgain( setup->dev, setup->ad_subdev);
452 if( ni_board( setup )->ref_eeprom_lsb >= 0 &&
453 ni_board( setup )->ref_eeprom_msb >= 0 )
455 voltage_reference = ni_get_reference( setup,
456 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
459 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
460 "correction. This might be fixable if you send us an eeprom dump\n"
461 "(see the demo/eeprom_dump program).\n");
462 voltage_reference = 5.0;
465 memset(&tmpl,0,sizeof(tmpl));
466 tmpl.insn = INSN_READ;
468 tmpl.subdev = setup->ad_subdev;
470 setup->n_observables = ni_num_observables;
472 /* 0 offset, low gain */
473 o = setup->observables + ni_zero_offset_low;
474 o->name = "ai, bipolar zero offset, low gain";
475 o->observe_insn = tmpl;
476 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_lowgain,AREF_OTHER)
477 | CR_ALT_SOURCE | CR_ALT_FILTER;
478 o->reference_source = REF_GND_GND;
481 /* 0 offset, high gain */
482 o = setup->observables + ni_zero_offset_high;
483 o->name = "ai, bipolar zero offset, high gain";
484 o->observe_insn = tmpl;
485 o->observe_insn.chanspec = CR_PACK(REF_GND_GND,bipolar_highgain,AREF_OTHER)
486 | CR_ALT_SOURCE | CR_ALT_FILTER;
487 o->reference_source = REF_GND_GND;
490 /* voltage reference */
491 o = setup->observables + ni_reference_low;
492 o->name = "ai, bipolar voltage reference, low gain";
493 o->observe_insn = tmpl;
494 o->observe_insn.chanspec = CR_PACK(REF_CALSRC_GND,bipolar_lowgain,AREF_OTHER)
495 | CR_ALT_SOURCE | CR_ALT_FILTER;
496 o->reference_source = REF_CALSRC_GND;
497 o->target = voltage_reference;
499 if(unipolar_lowgain>=0){
500 o = setup->observables + ni_unip_zero_offset_low;
501 o->name = "ai, unipolar zero offset, low gain";
502 o->observe_insn = tmpl;
503 o->observe_insn.chanspec =
504 CR_PACK(REF_GND_GND,unipolar_lowgain,AREF_OTHER)
505 | CR_ALT_SOURCE | CR_ALT_FILTER;
506 o->reference_source = REF_GND_GND;
507 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_lowgain );
509 o = setup->observables + ni_unip_reference_low;
510 o->name = "ai, unipolar voltage reference, low gain";
511 o->observe_insn = tmpl;
512 o->observe_insn.chanspec =
513 CR_PACK(REF_CALSRC_GND,unipolar_lowgain,AREF_OTHER)
514 | CR_ALT_SOURCE | CR_ALT_FILTER;
515 o->reference_source = REF_CALSRC_GND;
516 o->target = voltage_reference;
519 if(unipolar_highgain >= 0)
521 o = setup->observables + ni_unip_zero_offset_high;
522 o->name = "ai, unipolar zero offset, high gain";
523 o->observe_insn = tmpl;
524 o->observe_insn.chanspec =
525 CR_PACK(REF_GND_GND,unipolar_highgain,AREF_OTHER)
526 | CR_ALT_SOURCE | CR_ALT_FILTER;
527 o->reference_source = REF_GND_GND;
528 o->target = very_low_target( setup->dev, setup->ad_subdev, 0, unipolar_highgain );
531 if(setup->da_subdev >= 0)
532 ni_setup_ao_observables( setup );
535 /* for +-50V and +-20V ranges, the reference source goes 0V
536 * to 50V instead of 0V to 5V */
537 static unsigned int cal_gain_register_bits_611x( double reference, double *voltage )
541 bits = 200.0 * ( *voltage / reference );
542 if( bits > 200 ) bits = 200;
543 if( bits < 0 ) bits = 0;
545 *voltage = reference * ( bits / 200.0 );
549 static unsigned int ref_source_611x( unsigned int ref_source, unsigned int cal_gain_bits )
551 return ( ref_source & 0xf ) | ( ( cal_gain_bits << 4 ) & 0xff0 );
554 static void reference_target_611x( calibration_setup_t *setup,
555 observable *o, double master_reference, unsigned int range )
557 int cal_gain_reg_bits;
560 comedi_range *range_ptr;
562 range_ptr = comedi_get_range( setup->dev, setup->ad_subdev, 0, range );
563 assert( range_ptr != NULL );
564 if( range_ptr->max > 19.0 ) reference = 10 * master_reference;
565 else reference = master_reference;
566 target = range_ptr->max * 0.8;
568 cal_gain_reg_bits = cal_gain_register_bits_611x( reference, &target );
570 o->reference_source = ref_source_611x( REF_CALSRC_GND, cal_gain_reg_bits );
574 static void ni_setup_observables_611x( calibration_setup_t *setup )
579 double master_reference;
581 int num_ai_channels, num_ai_ranges;
582 static const int num_ao_channels = 2;
584 setup->sv_settling_time_ns = 10000000;
585 setup->sv_order = 14;
587 master_reference = ni_get_reference( setup,
588 ni_board( setup )->ref_eeprom_lsb, ni_board( setup )->ref_eeprom_msb );
590 memset(&tmpl,0,sizeof(tmpl));
591 tmpl.insn = INSN_READ;
593 tmpl.subdev = setup->ad_subdev;
595 num_ai_channels = comedi_get_n_channels( setup->dev, setup->ad_subdev );
596 assert( num_ai_channels >= 0 );
597 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
598 assert( num_ai_ranges >= 0 );
600 for( channel = 0; channel < num_ai_channels; channel++ )
602 for( range = 0; range < num_ai_ranges; range++ )
605 o = setup->observables + ni_zero_offset_611x( setup, channel, range );
606 assert( o->name == NULL );
607 asprintf( &o->name, "ai, ch %i, range %i, zero offset",
609 o->observe_insn = tmpl;
610 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
611 | CR_ALT_SOURCE | CR_ALT_FILTER;
612 o->reference_source = REF_GND_GND;
615 /* voltage reference */
616 o = setup->observables + ni_reference_611x( setup, channel, range );
617 assert( o->name == NULL );
618 asprintf( &o->name, "ai, ch %i, range %i, voltage reference",
620 o->observe_insn = tmpl;
621 o->observe_insn.chanspec = CR_PACK( channel, range, AREF_DIFF )
622 | CR_ALT_SOURCE | CR_ALT_FILTER;
623 reference_target_611x( setup, o, master_reference, range );
627 memset(&po_tmpl,0,sizeof(po_tmpl));
628 po_tmpl.insn = INSN_WRITE;
630 po_tmpl.subdev = setup->da_subdev;
632 for( channel = 0; channel < num_ao_channels; channel ++ )
634 static const int ai_range_for_ao = 2;
637 o = setup->observables + ni_ao_zero_offset_611x( setup, channel, 0 );
638 assert( o->name == NULL );
639 asprintf( &o->name, "ao ch %i, zero offset", channel );
640 o->preobserve_insn = po_tmpl;
641 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
642 o->preobserve_insn.data = o->preobserve_data;
643 o->observe_insn = tmpl;
644 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
645 | CR_ALT_SOURCE | CR_ALT_FILTER;
646 o->reference_source = REF_DAC_GND( channel );
647 set_target( setup, ni_ao_zero_offset_611x( setup, channel, 0 ), 0.0 );
650 o = setup->observables + ni_ao_reference_611x( setup, channel, 0 );
651 assert( o->name == NULL );
652 asprintf( &o->name, "ao ch %i, reference voltage", channel );
653 o->preobserve_insn = po_tmpl;
654 o->preobserve_insn.chanspec = CR_PACK( channel, 0, AREF_GROUND );
655 o->preobserve_insn.data = o->preobserve_data;
656 o->observe_insn = tmpl;
657 o->observe_insn.chanspec = CR_PACK( 0, ai_range_for_ao, AREF_DIFF )
658 | CR_ALT_SOURCE | CR_ALT_FILTER;
659 o->reference_source = REF_DAC_GND( channel );
660 set_target( setup, ni_ao_reference_611x( setup, channel, 0 ), 5.0 );
663 setup->n_observables = num_ao_observables_611x + 2 * num_ai_ranges * num_ai_channels;
666 static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup)
668 ni_caldac_layout_t layout;
670 init_ni_caldac_layout( &layout );
671 layout.adc_pregain_offset = 8;
672 layout.adc_postgain_offset = 2;
674 layout.adc_gain_fine = 1;
676 return cal_ni_generic( setup, &layout );
679 static int cal_ni_at_mio_16xe_50(calibration_setup_t *setup)
681 ni_caldac_layout_t layout;
683 init_ni_caldac_layout( &layout );
684 layout.adc_pregain_offset = 8;
685 layout.adc_postgain_offset = 2;
687 layout.adc_gain_fine = 1;
688 layout.dac_offset[ 0 ] = 6;
689 layout.dac_gain[ 0 ] = 4;
690 layout.dac_offset[ 1 ] = 7;
691 layout.dac_gain[ 1 ] = 5;
693 return cal_ni_generic( setup, &layout );
696 static int cal_ni_pci_mio_16xe_10(calibration_setup_t *setup)
698 ni_caldac_layout_t layout;
700 init_ni_caldac_layout( &layout );
701 layout.adc_pregain_offset = 8;
702 layout.adc_postgain_offset = 2;
703 layout.adc_postgain_offset_fine = 3;
705 layout.adc_gain_fine = 1;
706 layout.dac_offset[ 0 ] = 6;
707 layout.dac_gain[ 0 ] = 4;
708 layout.dac_offset[ 1 ] = 7;
709 layout.dac_gain[ 1 ] = 5;
711 return cal_ni_generic( setup, &layout );
714 static int cal_ni_at_mio_16e_1(calibration_setup_t *setup)
716 ni_caldac_layout_t layout;
718 init_ni_caldac_layout( &layout );
719 layout.adc_pregain_offset = 0;
720 layout.adc_postgain_offset = 1;
722 layout.adc_unip_offset = 2;
723 layout.dac_offset[0] = 5;
724 layout.dac_gain[0] = 6;
725 layout.dac_linearity[0] = 4;
726 layout.dac_offset[1] = 8;
727 layout.dac_gain[1] = 9;
728 layout.dac_linearity[1] = 7;
730 return cal_ni_generic( setup, &layout );
733 static int cal_ni_at_mio_16e_2(calibration_setup_t *setup)
735 return cal_ni_at_mio_16e_1(setup);
738 static int cal_ni_pci_mio_16e_1(calibration_setup_t *setup)
740 ni_caldac_layout_t layout;
742 init_ni_caldac_layout( &layout );
743 layout.adc_pregain_offset = 0;
744 layout.adc_postgain_offset = 1;
745 layout.adc_unip_offset = 2;
747 layout.dac_offset[ 0 ] = 5;
748 layout.dac_gain[ 0 ] = 6;
749 layout.dac_linearity[ 0 ] = 4;
750 layout.dac_offset[ 1 ] = 8;
751 layout.dac_gain[ 1 ] = 9;
752 layout.dac_linearity[ 1 ] = 7;
754 return cal_ni_generic( setup, &layout );
757 static int cal_ni_pci_6014(calibration_setup_t *setup)
759 ni_caldac_layout_t layout;
761 init_ni_caldac_layout( &layout );
762 layout.adc_pregain_offset = 0;
763 layout.adc_postgain_offset = 4;
764 layout.adc_pregain_offset_fine = 8;
766 layout.dac_offset[0] = 6;
767 layout.dac_offset_fine[0] = 10;
768 layout.dac_gain[0] = 7;
769 layout.dac_gain_fine[0] = 11;
770 layout.dac_offset[1] = 9;
771 layout.dac_offset_fine[1] = 1;
772 layout.dac_gain[1] = 3;
773 layout.dac_gain_fine[1] = 5;
774 return cal_ni_generic( setup, &layout );
777 static int cal_ni_pci_6032e(calibration_setup_t *setup)
779 ni_caldac_layout_t layout;
781 init_ni_caldac_layout( &layout );
782 layout.adc_pregain_offset = 8;
783 layout.adc_postgain_offset = 2;
784 layout.adc_postgain_offset_fine = 3;
786 layout.adc_gain_fine = 1;
788 return cal_ni_generic( setup, &layout );
791 static int cal_ni_pci_6035e(calibration_setup_t *setup)
793 /* this is for the ad8804_debug caldac */
794 ni_caldac_layout_t layout;
796 init_ni_caldac_layout( &layout );
797 layout.adc_pregain_offset = 0;
798 layout.adc_pregain_offset_fine = 8;
799 layout.adc_postgain_offset = 4;
801 layout.dac_offset[ 0 ] = 6;
802 layout.dac_gain[ 0 ] = 11;
803 layout.dac_linearity[ 0 ] = 10;
804 layout.dac_offset[ 1 ] = 9;
805 layout.dac_gain[ 1 ] = 5;
806 layout.dac_linearity[ 1 ] = 1;
808 return cal_ni_generic( setup, &layout );
811 static int cal_ni_pci_6036e(calibration_setup_t *setup)
813 ni_caldac_layout_t layout;
815 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
817 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
818 "for this calibration to work properly\n" );
821 /* this is for the ad8804_debug caldac */
822 init_ni_caldac_layout( &layout );
823 layout.adc_pregain_offset = 0;
824 layout.adc_postgain_offset = 4;
825 layout.adc_pregain_offset_fine = 8;
827 layout.dac_offset[ 0 ] = 6;
828 layout.dac_gain[ 0 ] = 7;
829 layout.dac_gain_fine[ 0 ] = 11;
830 layout.dac_linearity[ 0 ] = 10;
831 layout.dac_offset[ 1 ] = 9;
832 layout.dac_gain[ 1 ] = 3;
833 layout.dac_gain_fine[ 1 ] = 5;
834 layout.dac_linearity[ 1 ] = 1;
836 return cal_ni_generic( setup, &layout );
839 static int cal_ni_pci_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 = 8;
851 layout.adc_postgain_offset = 4;
852 layout.adc_unip_offset = 7;
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_pxi_6071e(calibration_setup_t *setup)
865 ni_caldac_layout_t layout;
867 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
869 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
870 "for this calibration to work properly\n" );
873 init_ni_caldac_layout( &layout );
874 layout.adc_pregain_offset = 0;
875 layout.adc_pregain_offset_fine = 8;
876 layout.adc_postgain_offset = 4;
878 layout.dac_offset[ 0 ] = 6;
879 layout.dac_gain[ 0 ] = 11;
880 layout.dac_linearity[ 0 ] = 10;
881 layout.dac_offset[ 1 ] = 9;
882 layout.dac_gain[ 1 ] = 5;
883 layout.dac_linearity[ 1 ] = 1;
884 return cal_ni_generic( setup, &layout );
887 static int cal_ni_at_mio_16e_10(calibration_setup_t *setup)
889 ni_caldac_layout_t layout;
891 if(comedi_get_version_code(setup->dev) <= COMEDI_VERSION_CODE(0, 7, 68))
893 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
894 "for this calibration to work properly\n" );
896 init_ni_caldac_layout( &layout );
897 layout.adc_pregain_offset = 0;
898 layout.adc_pregain_offset_fine = 8;
899 layout.adc_postgain_offset = 4;
901 layout.adc_unip_offset = 7;
902 layout.dac_offset[ 0 ] = 6;
903 layout.dac_gain[ 0 ] = 11;
904 layout.dac_linearity[ 0 ] = 10;
905 layout.dac_offset[ 1 ] = 9;
906 layout.dac_gain[ 1 ] = 5;
907 layout.dac_linearity[1] = 1;
908 return cal_ni_generic( setup, &layout );
911 static int cal_ni_pci_mio_16xe_50(calibration_setup_t *setup)
913 ni_caldac_layout_t layout;
915 init_ni_caldac_layout( &layout );
916 layout.adc_pregain_offset = 8;
917 layout.adc_postgain_offset = 2;
919 layout.adc_gain_fine = 1;
920 layout.adc_unip_offset = 7;
921 layout.dac_offset[ 0 ] = 6;
922 layout.dac_gain[ 0 ] = 4;
923 layout.dac_offset[ 1 ] = 7;
924 layout.dac_gain[ 1 ] = 5;
926 return cal_ni_generic( setup, &layout );
929 static int cal_ni_pci_6023e(calibration_setup_t *setup)
931 /* for comedi-0.7.65 */
932 ni_caldac_layout_t layout;
934 init_ni_caldac_layout( &layout );
935 layout.adc_pregain_offset = 8; /* possibly wrong */
936 layout.adc_pregain_offset_fine = 0;
937 layout.adc_postgain_offset = 4;
940 return cal_ni_generic( setup, &layout );
943 static int cal_ni_pci_6024e(calibration_setup_t *setup)
945 ni_caldac_layout_t layout;
947 init_ni_caldac_layout( &layout );
948 layout.adc_pregain_offset = 0;
949 layout.adc_postgain_offset = 4;
950 layout.adc_pregain_offset_fine = 8;
952 layout.dac_offset[ 0 ] = 6;
953 layout.dac_gain[ 0 ] = 11;
954 layout.dac_linearity[ 0 ] = 10;
955 layout.dac_offset[ 1 ] = 9;
956 layout.dac_gain[ 1 ] = 5;
957 layout.dac_linearity[ 1 ] = 1;
959 return cal_ni_generic( setup, &layout );
962 static int cal_ni_pci_6025e(calibration_setup_t *setup)
964 ni_caldac_layout_t layout;
966 init_ni_caldac_layout( &layout );
967 layout.adc_pregain_offset = 0;
968 layout.adc_postgain_offset = 4;
969 layout.adc_pregain_offset_fine = 8;
971 layout.dac_offset[ 0 ] = 6;
972 layout.dac_gain[ 0 ] = 11;
973 layout.dac_linearity[ 0 ] = 10;
974 layout.dac_offset[ 1 ] = 9;
975 layout.dac_gain[ 1 ] = 5;
976 layout.dac_linearity[ 1 ] = 1;
978 return cal_ni_generic( setup, &layout );
981 static int cal_ni_pci_6052e(calibration_setup_t *setup)
984 * This board has noisy caldacs
986 * The NI documentation says (true mb88341 addressing):
987 * 0, 8 AI pregain (coarse, fine)
990 * 14, 7 AI unipolar offset
996 * 10, 6 AO1 reference
999 * For us, these map to (ad8804 channels)
1001 * 0, 1 AI pregain (coarse, fine)
1004 * 7 AI unipolar offset
1007 * 1, 2 AO0 reference
1010 * 5, 6 AO1 reference
1013 * or, with mb88341 channels
1016 * 7, 3 AO0 reference
1019 * 9, 5 AO1 reference
1023 ni_caldac_layout_t layout;
1025 init_ni_caldac_layout( &layout );
1026 layout.adc_pregain_offset = 0;
1027 layout.adc_postgain_offset = 2;
1028 layout.adc_gain = 4;
1029 layout.adc_unip_offset = 6;
1030 layout.adc_unip_offset_fine = 7;
1031 layout.adc_pregain_offset_fine = 1;
1032 layout.adc_postgain_offset_fine = 3;
1033 layout.adc_gain_fine = 5;
1035 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1036 "for this calibration to work properly\n" );
1037 /* this works when the first two caldacs are ad8804_debug */
1038 layout.dac_offset[ 0 ] = 16 + 3;
1039 layout.dac_gain[ 0 ] = 16 + 1;
1040 layout.dac_gain_fine[ 0 ] = 16 + 2;
1041 layout.dac_linearity[ 0 ] = 16 + 0;
1042 layout.dac_offset[ 1 ] = 16 + 7;
1043 layout.dac_gain[ 1 ] = 16 + 5;
1044 layout.dac_gain_fine[ 1 ] = 16 + 6;
1045 layout.dac_linearity[ 1 ] = 16 + 4;
1047 return cal_ni_generic( setup, &layout );
1050 static int cal_ni_daqcard_ai_16e_4(calibration_setup_t *setup)
1052 ni_caldac_layout_t layout;
1054 init_ni_caldac_layout( &layout );
1055 layout.adc_pregain_offset = 0;
1056 layout.adc_postgain_offset = 1;
1057 layout.adc_gain = 3;
1058 layout.adc_unip_offset = 2;
1060 return cal_ni_generic( setup, &layout );
1063 static int adc_offset_611x( unsigned int channel )
1065 return 2 * channel + 2;
1067 static int adc_gain_611x( unsigned int channel )
1069 return 2 * channel + 1;
1071 static int dac_offset_611x( unsigned int channel )
1073 return 12 + 2 + 2 * channel;
1075 static int dac_gain_611x( unsigned int channel )
1077 return 12 + 1 + 2 * channel;
1079 static int cal_ni_pci_611x( calibration_setup_t *setup )
1081 generic_layout_t layout;
1083 init_generic_layout( &layout );
1084 layout.adc_offset = adc_offset_611x;
1085 layout.adc_gain = adc_gain_611x;
1086 layout.dac_offset = dac_offset_611x;
1087 layout.dac_gain = dac_gain_611x;
1088 layout.adc_high_observable = ni_reference_611x;
1089 layout.adc_ground_observable = ni_zero_offset_611x;
1090 layout.dac_high_observable = ni_ao_reference_611x;
1091 layout.dac_ground_observable = ni_ao_zero_offset_611x;
1093 return generic_cal_by_channel_and_range( setup, &layout );
1096 static int cal_ni_pci_mio_16e_4( calibration_setup_t *setup )
1098 ni_caldac_layout_t layout;
1100 init_ni_caldac_layout( &layout );
1101 layout.adc_pregain_offset = 8;
1102 layout.adc_postgain_offset = 4;
1103 layout.adc_gain = 2;
1104 layout.adc_unip_offset = 7;
1105 layout.dac_offset[ 0 ] = 6;
1106 layout.dac_gain[ 0 ] = 11;
1107 layout.dac_linearity[ 0 ] = 10;
1108 layout.dac_offset[ 1 ] = 9;
1109 layout.dac_gain[ 1 ] = 5;
1110 layout.dac_linearity[ 1 ] = 1;
1112 return cal_ni_generic( setup, &layout );
1115 static int cal_ni_daqcard_6062e( calibration_setup_t *setup )
1117 ni_caldac_layout_t layout;
1119 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 66 ) )
1121 DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
1122 "for this calibration to work properly\n" );
1124 init_ni_caldac_layout( &layout );
1125 layout.adc_pregain_offset = 8;
1126 layout.adc_postgain_offset = 4;
1127 layout.adc_gain = 2;
1128 layout.adc_unip_offset = 7;
1129 layout.dac_offset[ 0 ] = 6;
1130 layout.dac_gain[ 0 ] = 11;
1131 layout.dac_linearity[ 0 ] = 10;
1132 layout.dac_offset[ 1 ] = 9;
1133 layout.dac_gain[ 1 ] = 5;
1134 layout.dac_linearity[ 1 ] = 1;
1136 return cal_ni_generic( setup, &layout );
1139 static int cal_ni_daqcard_6024e( calibration_setup_t *setup )
1141 ni_caldac_layout_t layout;
1143 init_ni_caldac_layout( &layout );
1145 layout.adc_pregain_offset = 0;
1146 layout.adc_postgain_offset = 4;
1147 layout.adc_gain = 2;
1148 //layout.adc_unip_offset = 7;
1149 layout.dac_offset[ 0 ] = 6;
1150 layout.dac_gain[ 0 ] = 3;
1151 //layout.dac_linearity[ 0 ] = 10;
1152 layout.dac_offset[ 1 ] = 1;
1153 layout.dac_gain[ 1 ] = 5;
1154 //layout.dac_linearity[ 1 ] = 1;
1156 return cal_ni_generic( setup, &layout );
1159 static int cal_ni_daqcard_6036e( calibration_setup_t *setup )
1161 ni_caldac_layout_t layout;
1163 if( comedi_get_version_code( setup->dev ) <= COMEDI_VERSION_CODE( 0, 7, 68 ) )
1165 DPRINT(0, "WARNING: you need comedi driver version 0.7.69 or later\n"
1166 "for this calibration to work properly\n" );
1169 init_ni_caldac_layout( &layout );
1171 layout.adc_pregain_offset = 0;
1172 layout.adc_pregain_offset_fine = 8;
1173 layout.adc_postgain_offset = 4;
1174 layout.adc_gain = 2;
1176 layout.dac_offset[0] = 6;
1177 layout.dac_gain[0] = 7;
1178 layout.dac_gain_fine[ 0 ] = 11;
1179 layout.dac_linearity[0] = 10;
1181 layout.dac_offset[ 1 ] = 9;
1182 layout.dac_gain[ 1 ] = 3;
1183 layout.dac_gain_fine[ 1 ] = 5;
1184 layout.dac_linearity[1] = 1;
1186 return cal_ni_generic( setup, &layout );
1189 static void prep_adc_caldacs_generic( calibration_setup_t *setup,
1190 const ni_caldac_layout_t *layout, unsigned int range )
1194 if( setup->old_calibration == NULL )
1196 reset_caldac( setup, layout->adc_pregain_offset );
1197 reset_caldac( setup, layout->adc_postgain_offset );
1198 reset_caldac( setup, layout->adc_gain );
1199 reset_caldac( setup, layout->adc_pregain_offset_fine );
1200 reset_caldac( setup, layout->adc_postgain_offset_fine );
1201 reset_caldac( setup, layout->adc_gain_fine );
1202 reset_caldac( setup, layout->adc_unip_offset );
1203 reset_caldac( setup, layout->adc_unip_offset_fine );
1206 retval = comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1207 0, range, AREF_GROUND, setup->old_calibration );
1210 DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" );
1211 reset_caldac( setup, layout->adc_pregain_offset );
1212 reset_caldac( setup, layout->adc_postgain_offset );
1213 reset_caldac( setup, layout->adc_gain );
1214 reset_caldac( setup, layout->adc_pregain_offset_fine );
1215 reset_caldac( setup, layout->adc_postgain_offset_fine );
1216 reset_caldac( setup, layout->adc_gain_fine );
1217 reset_caldac( setup, layout->adc_unip_offset );
1218 reset_caldac( setup, layout->adc_unip_offset_fine );
1223 static void prep_dac_caldacs_generic( calibration_setup_t *setup,
1224 const ni_caldac_layout_t *layout, unsigned int channel, unsigned int range )
1228 if( setup->da_subdev < 0 ) return;
1230 if( setup->old_calibration == NULL )
1232 reset_caldac( setup, layout->dac_offset[ channel ] );
1233 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1234 reset_caldac( setup, layout->dac_gain[ channel ] );
1235 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1236 reset_caldac( setup, layout->dac_linearity[ channel ] );
1239 retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev,
1240 channel, range, AREF_GROUND, setup->old_calibration );
1243 DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" );
1244 reset_caldac( setup, layout->dac_offset[ channel ] );
1245 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1246 reset_caldac( setup, layout->dac_gain[ channel ] );
1247 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1248 reset_caldac( setup, layout->dac_linearity[ channel ] );
1253 static void prep_adc_for_dac( calibration_setup_t *setup, int observable )
1255 unsigned int adc_range;
1258 if( observable < 0 ) return;
1260 chanspec = setup->observables[ observable ].observe_insn.chanspec;
1261 adc_range = CR_RANGE( chanspec );
1263 comedi_apply_parsed_calibration( setup->dev, setup->ad_subdev,
1264 0, adc_range, 0, setup->new_calibration );
1267 static int cal_ni_generic( calibration_setup_t *setup, const ni_caldac_layout_t *layout )
1269 comedi_calibration_setting_t *current_cal;
1273 int ai_unipolar_lowgain, ai_bipolar_lowgain;
1275 num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
1276 assert( num_ai_ranges > 0 );
1278 ai_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->ad_subdev );
1279 ai_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->ad_subdev );
1281 prep_adc_caldacs_generic( setup, layout, ai_bipolar_lowgain );
1283 current_cal = sc_alloc_calibration_setting( setup );
1284 current_cal->subdevice = setup->ad_subdev;
1285 reset_caldac( setup, layout->adc_gain_fine );
1286 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1287 ni_reference_low, layout->adc_gain );
1288 reset_caldac( setup, layout->adc_postgain_offset_fine );
1289 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1290 ni_zero_offset_high, layout->adc_postgain_offset );
1291 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1292 ni_zero_offset_high, layout->adc_postgain_offset_fine );
1293 reset_caldac( setup, layout->adc_pregain_offset_fine );
1294 generic_do_cal( setup, current_cal, ni_zero_offset_high, layout->adc_pregain_offset );
1295 generic_do_relative( setup, current_cal, ni_zero_offset_low,
1296 ni_reference_low, layout->adc_gain_fine );
1297 generic_do_cal( setup, current_cal, ni_zero_offset_high,
1298 layout->adc_pregain_offset_fine );
1299 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1300 sc_push_aref( current_cal, SC_ALL_AREFS );
1301 if( layout->adc_unip_offset >= 0 )
1303 sc_push_range( current_cal, SC_ALL_RANGES );
1306 for( range = 0; range < num_ai_ranges; range++ )
1308 if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
1309 sc_push_range( current_cal, range );
1313 /* do seperate unipolar calibration if appropriate */
1314 if( ai_unipolar_lowgain >= 0 )
1316 current_cal = sc_alloc_calibration_setting( setup );
1317 current_cal->subdevice = setup->ad_subdev;
1318 if( layout->adc_unip_offset >= 0 )
1320 reset_caldac( setup, layout->adc_unip_offset_fine );
1321 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1322 layout->adc_unip_offset );
1323 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1324 layout->adc_unip_offset_fine );
1325 /* if we don't have a unipolar offset caldac, do a fully
1326 * independent calibration for unipolar ranges */
1329 prep_adc_caldacs_generic( setup, layout, ai_unipolar_lowgain );
1330 generic_peg( setup, ni_unip_zero_offset_low,
1331 layout->adc_pregain_offset, 1 );
1332 generic_peg( setup, ni_unip_zero_offset_low,
1333 layout->adc_postgain_offset, 1 );
1334 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1335 ni_unip_reference_low, layout->adc_gain );
1336 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1337 ni_unip_zero_offset_high, layout->adc_postgain_offset );
1338 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1339 ni_unip_zero_offset_high, layout->adc_postgain_offset_fine );
1340 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1341 layout->adc_pregain_offset );
1342 generic_do_relative( setup, current_cal, ni_unip_zero_offset_low,
1343 ni_unip_reference_low, layout->adc_gain_fine );
1344 generic_do_cal( setup, current_cal, ni_unip_zero_offset_high,
1345 layout->adc_pregain_offset_fine );
1347 for( range = 0; range < num_ai_ranges; range++ )
1349 if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
1350 sc_push_range( current_cal, range );
1352 sc_push_channel( current_cal, SC_ALL_CHANNELS );
1353 sc_push_aref( current_cal, SC_ALL_AREFS );
1355 if( setup->da_subdev >= 0 && setup->do_output )
1357 unsigned int channel, range;
1358 int ao_unipolar_lowgain = get_unipolar_lowgain( setup->dev, setup->da_subdev );
1359 int ao_bipolar_lowgain = get_bipolar_lowgain( setup->dev, setup->da_subdev );
1362 for( channel = 0; channel < 2; channel++ )
1364 num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, channel );
1365 prep_dac_caldacs_generic( setup, layout, channel, ao_bipolar_lowgain );
1366 prep_adc_for_dac( setup, ni_ao_reference( channel ) );
1368 current_cal = sc_alloc_calibration_setting( setup );
1369 current_cal->subdevice = setup->da_subdev;
1370 generic_do_linearity( setup, current_cal, ni_ao_zero_offset( channel ),
1371 ni_ao_mid_linearity( channel ), ni_ao_reference( channel ),
1372 layout->dac_linearity[ channel ] );
1373 reset_caldac(setup, layout->dac_offset_fine[channel]);
1374 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1375 layout->dac_offset[ channel ] );
1376 generic_do_cal( setup, current_cal, ni_ao_zero_offset( channel ),
1377 layout->dac_offset_fine[ channel ] );
1378 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1379 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1380 layout->dac_gain[ channel ] );
1381 generic_do_cal( setup, current_cal, ni_ao_reference( channel ),
1382 layout->dac_gain_fine[ channel ] );
1383 sc_push_channel( current_cal, channel );
1384 for( range = 0; range < num_ao_ranges; range++ )
1386 if( is_bipolar( setup->dev, setup->da_subdev, channel, range ) )
1387 sc_push_range( current_cal, range );
1389 sc_push_aref( current_cal, SC_ALL_AREFS );
1391 if( ao_unipolar_lowgain >= 0 )
1393 prep_dac_caldacs_generic( setup, layout, channel, ao_unipolar_lowgain );
1395 current_cal = sc_alloc_calibration_setting( setup );
1396 current_cal->subdevice = setup->da_subdev;
1397 generic_do_linearity( setup, current_cal, ni_ao_unip_low_linearity( channel ),
1398 ni_ao_unip_mid_linearity( channel ), ni_ao_unip_reference( channel ),
1399 layout->dac_linearity[ channel ] );
1400 reset_caldac( setup, layout->dac_offset_fine[ channel ] );
1401 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1402 layout->dac_offset[ channel ] );
1403 generic_do_cal( setup, current_cal, ni_ao_unip_zero_offset( channel),
1404 layout->dac_offset_fine[ channel ] );
1405 reset_caldac( setup, layout->dac_gain_fine[ channel ] );
1406 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1407 layout->dac_gain[ channel ] );
1408 generic_do_cal( setup, current_cal, ni_ao_unip_reference( channel ),
1409 layout->dac_gain_fine[ channel ] );
1410 sc_push_channel( current_cal, channel );
1411 for( range = 0; range < num_ao_ranges; range++ )
1413 if( is_unipolar( setup->dev, setup->da_subdev, channel, range ) )
1414 sc_push_range( current_cal, range );
1416 sc_push_aref( current_cal, SC_ALL_AREFS );
1421 retval = write_calibration_file( setup );
1426 static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc)
1432 lsb=read_eeprom( setup, lsb_loc );
1433 msb=read_eeprom( setup, msb_loc );
1434 assert( lsb >=0 && msb >= 0 );
1435 DPRINT(0,"eeprom reference lsb=%d msb=%d\n", lsb, msb);
1437 uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 );
1438 ref=5.000+1.0e-6*uv;
1439 DPRINT(0, "resulting reference voltage: %g\n", ref );
1440 if( fabs( ref - 5.0 ) > 0.005 )
1441 DPRINT( 0, "WARNING: eeprom indicates reference is more than 5mV away\n"
1442 "from 5V. Possible bad eeprom address?\n" );
1448 NI 671x and 673x support
1451 static const int channels_per_ad8804 = 16;
1453 static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel)
1455 int ad8804_gain_channels[4] = {8, 2, 11, 5};
1456 int caldac_channel = ad8804_gain_channels[ao_channel % 4];
1457 int caldac_index = ao_channel / 4;
1458 /* just guessing that second ad8804 is works for ao channels 4-7
1459 * the same as the first ad8804 works for ao channels 0-3 */
1460 return caldac_index * channels_per_ad8804 + caldac_channel;
1462 static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel)
1464 int ad8804_linearity_channels[4] = {4, 10, 1, 0};
1465 int caldac_channel = ad8804_linearity_channels[ao_channel % 4];
1466 int caldac_index = ao_channel / 4;
1468 return caldac_index * channels_per_ad8804 + caldac_channel;
1470 static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel)
1472 int ad8804_offset_channels[4] = {7, 6, 9, 3};
1473 int caldac_channel = ad8804_offset_channels[ao_channel % 4];
1474 int caldac_index = ao_channel / 4;
1476 return caldac_index * channels_per_ad8804 + caldac_channel;
1479 static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup,
1480 unsigned int channel, unsigned int ao_range )
1482 return 3 * channel + 0;
1485 static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup,
1486 unsigned int channel, unsigned int ao_range )
1488 return 3 * channel + 1;
1491 static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup,
1492 unsigned int channel, unsigned int ao_range )
1494 return 3 * channel + 2;
1497 static const double ni67xx_unitless_adc_offset = 0.5;
1499 /* determine conversion factor between actual voltage and
1500 * interval [0,1) returned by reads from the calibration adc
1503 static double ni67xx_unitless_adc_slope(calibration_setup_t *setup)
1505 double reference_in_volts;
1506 double reference_unitless;
1510 comedi_range *range;
1511 static const int maxdata = 0x10000;
1514 if(ni_board(setup)->ref_eeprom_lsb >= 0 &&
1515 ni_board(setup)->ref_eeprom_msb >= 0)
1517 reference_in_volts = ni_get_reference(setup,
1518 ni_board(setup)->ref_eeprom_lsb, ni_board(setup)->ref_eeprom_msb );
1521 DPRINT( 0, "WARNING: unknown eeprom address for reference voltage\n"
1522 "correction. This might be fixable if you send us an eeprom dump\n"
1523 "(see the demo/eeprom_dump program).\n");
1524 reference_in_volts = 5.0;
1527 memset(&insn, 0, sizeof(insn));
1528 insn.insn = INSN_READ;
1530 insn.subdev = setup->ad_subdev;
1532 insn.chanspec = CR_PACK(0, 0, AREF_GROUND) | CR_ALT_SOURCE;
1533 retval = comedi_do_insn(setup->dev, &insn);
1534 assert(retval >= 0);
1536 range = comedi_get_range(setup->dev, setup->ad_subdev, 0, 0);
1538 reference_unitless = comedi_to_phys(data, range, maxdata);
1540 slope = (reference_unitless - ni67xx_unitless_adc_offset) / reference_in_volts;
1545 /* calibration adc uses RANGE_UNKNOWN, so it will return a value from
1546 0.0 to 1.0 instead of a voltage, so we need to renormalize. */
1547 static void ni67xx_set_target( calibration_setup_t *setup, int obs, double target, double slope)
1549 set_target(setup, obs, target);
1550 /* convert target from volts to interval [0,1) which calibration
1552 setup->observables[obs].target *= slope;
1553 setup->observables[obs].target += ni67xx_unitless_adc_offset;
1556 static void ni67xx_setup_observables( calibration_setup_t *setup )
1558 comedi_insn tmpl, po_tmpl;
1560 int num_ao_channels;
1564 slope = ni67xx_unitless_adc_slope(setup);
1566 /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */
1567 setup->sv_order = 1;
1569 num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev);
1570 assert(num_ao_channels >= 0);
1572 memset( &tmpl, 0, sizeof(tmpl) );
1573 tmpl.insn = INSN_READ;
1575 tmpl.subdev = setup->ad_subdev;
1577 memset( &po_tmpl, 0, sizeof(po_tmpl) );
1578 po_tmpl.insn = INSN_WRITE;
1580 po_tmpl.subdev = setup->da_subdev;
1582 setup->n_observables = 0;
1584 for(i = 0; i < num_ao_channels; i++)
1586 o = setup->observables + ni67xx_ao_ground_observable_index( setup,
1588 o->reference_source = -1;
1589 assert( o->name == NULL );
1590 asprintf(&o->name, "dac%i ground, ground referenced", i);
1591 o->preobserve_insn = po_tmpl;
1592 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1593 o->preobserve_insn.data = o->preobserve_data;
1594 o->observe_insn = tmpl;
1595 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1596 ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0, slope);
1597 setup->n_observables++;
1599 o = setup->observables + ni67xx_ao_mid_observable_index( setup,
1601 o->reference_source = -1;
1602 assert( o->name == NULL );
1603 asprintf(&o->name, "dac%i mid, ground referenced", i);
1604 o->preobserve_insn = po_tmpl;
1605 o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1606 o->preobserve_insn.data = o->preobserve_data;
1607 o->observe_insn = tmpl;
1608 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1609 ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0, slope);
1610 setup->n_observables++;
1612 o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0);
1613 o->reference_source = -1;
1614 assert( o->name == NULL );
1615 asprintf(&o->name, "dac%i high, ground referenced", i);
1616 o->preobserve_insn = po_tmpl;
1617 o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND );
1618 o->preobserve_insn.data = o->preobserve_data;
1619 o->observe_insn = tmpl;
1620 o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND);
1621 ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0, slope);
1622 setup->n_observables++;
1628 static int cal_ni_pci_6711(calibration_setup_t *setup)
1630 generic_layout_t layout;
1632 init_generic_layout( &layout );
1633 layout.dac_gain = ni67xx_ao_gain_caldac;
1634 layout.dac_linearity = ni67xx_ao_linearity_caldac;
1635 layout.dac_offset = ni67xx_ao_offset_caldac;
1636 layout.dac_high_observable = ni67xx_ao_high_observable_index;
1637 layout.dac_mid_observable = ni67xx_ao_mid_observable_index;
1638 layout.dac_ground_observable = ni67xx_ao_ground_observable_index;
1639 layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 );
1640 return generic_cal_ao(setup, &layout);