From 7041bcca954c83a6abcfc4d7ee9a71078ff564b7 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Tue, 29 Apr 2003 01:00:22 +0000 Subject: [PATCH] added support for calibrating analog output linearity --- comedi_calibrate/calib.h | 2 + comedi_calibrate/cb.c | 3 +- comedi_calibrate/cb64.c | 3 +- comedi_calibrate/comedi_calibrate.c | 119 +++++++++- comedi_calibrate/ni.c | 347 +++++++++++++++++----------- 5 files changed, 333 insertions(+), 141 deletions(-) diff --git a/comedi_calibrate/calib.h b/comedi_calibrate/calib.h index bdec910..e97b2ad 100644 --- a/comedi_calibrate/calib.h +++ b/comedi_calibrate/calib.h @@ -115,6 +115,8 @@ void cal1( calibration_setup_t *setup, int obs, int dac); void cal1_fine( calibration_setup_t *setup, int obs, int dac); void cal_binary( calibration_setup_t *setup, int obs, int dac); void cal_postgain_binary( calibration_setup_t *setup, int obs1, int obs2, int dac); +void cal_relative_binary( calibration_setup_t *setup, int obs1, int obs2, int dac); +void cal_linearity_binary( calibration_setup_t *setup, int obs1, int obs2, int obs3, int dac); /* misc and temp */ diff --git a/comedi_calibrate/cb.c b/comedi_calibrate/cb.c index faa81df..ea76138 100644 --- a/comedi_calibrate/cb.c +++ b/comedi_calibrate/cb.c @@ -1,7 +1,6 @@ /*************************************************************************** cb.c - calibration support for some Measurement computing boards. - Based on ni.c by David Schleef. - ------------------- + ------------------- begin : Sat Apr 27 2002 copyright : (C) 2002,2003 by Frank Mori Hess diff --git a/comedi_calibrate/cb64.c b/comedi_calibrate/cb64.c index d7948f7..8d87121 100644 --- a/comedi_calibrate/cb64.c +++ b/comedi_calibrate/cb64.c @@ -1,6 +1,5 @@ /*************************************************************************** cb64.c - calibration support for some Measurement computing boards. - Based on ni.c by David Schleef. ------------------- begin : Sat Apr 27 2002 @@ -67,7 +66,7 @@ static struct board_struct boards[]={ { "pci-das6025", STATUS_DONE, setup_cb_pci_60xx }, { "pci-das6034", STATUS_GUESS, setup_cb_pci_60xx }, { "pci-das6035", STATUS_GUESS, setup_cb_pci_60xx }, - { "pci-das4020/12", STATUS_SOME, setup_cb_pci_4020 }, + { "pci-das4020/12", STATUS_DONE, setup_cb_pci_4020 }, }; static const int num_boards = ( sizeof(boards) / sizeof(boards[0]) ); diff --git a/comedi_calibrate/comedi_calibrate.c b/comedi_calibrate/comedi_calibrate.c index eca9f51..f9fef0b 100644 --- a/comedi_calibrate/comedi_calibrate.c +++ b/comedi_calibrate/comedi_calibrate.c @@ -2,18 +2,17 @@ A little auto-calibration utility, for boards that support it. + copyright (C) 1999,2000,2001,2002 by David Schleef + copyright (C) 2003 by Frank Mori Hess + A few things need improvement here: - current system gets "close", but doesn't do any fine-tuning - - no pre/post gain discrimination for the - A/D zero offset. - should read (and use) the actual reference voltage value from eeprom - statistics would be nice, to show how good the calibration is. - doesn't check unipolar ranges - - "alternate calibrations" would be cool--to - accurately measure 0 in a unipolar range - more portable */ @@ -525,6 +524,11 @@ void cal_binary( calibration_setup_t *setup, int obs, int dac) } void cal_postgain_binary( calibration_setup_t *setup, int obs1, int obs2, int dac) +{ + cal_relative_binary( setup, obs1, obs2, dac ); +} + +void cal_relative_binary( calibration_setup_t *setup, int obs1, int obs2, int dac) { int x0, x1, x2, x, polarity; double y0, y1, y2; @@ -544,12 +548,101 @@ void cal_postgain_binary( calibration_setup_t *setup, int obs1, int obs2, int da new_sv_init(&sv1, setup->dev, setup->ad_subdev,chanspec1); sv1.settling_time_ns = setup->settling_time_ns; new_sv_measure( setup->dev, &sv1); - y0 = sv1.average; + + preobserve( setup, obs2); + new_sv_init(&sv2, setup->dev, setup->ad_subdev,chanspec2); + sv2.settling_time_ns = setup->settling_time_ns; + new_sv_measure( setup->dev, &sv2); + y0 = y1 = y2 = sv1.average - sv2.average; + + bit = 1; + while( ( bit << 1 ) < setup->caldacs[dac].maxdata ) + bit <<= 1; + for( ; bit; bit >>= 1 ) + { + x2 = x1 | bit; + + update_caldac( setup, dac, x2 ); + usleep(100000); + + preobserve( setup, obs1); + new_sv_init(&sv1, setup->dev, setup->ad_subdev,chanspec1); + sv1.settling_time_ns = setup->settling_time_ns; + new_sv_measure( setup->dev, &sv1); + + preobserve( setup, obs2); + new_sv_init(&sv2, setup->dev, setup->ad_subdev,chanspec2); + sv2.settling_time_ns = setup->settling_time_ns; + new_sv_measure( setup->dev, &sv2); + y2 = sv1.average - sv2.average; + + DPRINT(3,"trying %d, result %g, target %g\n",x2,y2,target); + + if( (y2 - y0) > 0.0 ) polarity = 1; + else polarity = -1; + + if( (y2 - target) * polarity < 0.0 ){ + x1 = x2; + y1 = y2; + } + + if(verbose>=3){ + preobserve( setup, obs1); + measure_observable( setup, obs1); + preobserve( setup, obs2); + measure_observable( setup, obs2); + } + } + + if( fabs( y1 - target ) < fabs( y2 - target ) ) + x = x1; + else + x = x2; + update_caldac( setup, dac, x ); + DPRINT(0,"caldac[%d] set to %d\n",dac,x); + if(verbose>=3){ + preobserve( setup, obs1); + measure_observable( setup, obs1); + preobserve( setup, obs2); + measure_observable( setup, obs2); + } +} + +void cal_linearity_binary( calibration_setup_t *setup, int obs1, int obs2, int obs3, int dac) +{ + int x0, x1, x2, x, polarity; + double y0, y1, y2; + new_sv_t sv1, sv2, sv3; + double target = ( setup->observables[obs3].target - setup->observables[obs2].target ) / + ( setup->observables[obs2].target - setup->observables[obs1].target ); + unsigned int chanspec1 = setup->observables[obs1].observe_insn.chanspec; + unsigned int chanspec2 = setup->observables[obs2].observe_insn.chanspec; + unsigned int chanspec3 = setup->observables[obs3].observe_insn.chanspec; + unsigned int bit; + + DPRINT(0,"postgain linearity: %s,\n%s,\n%s\n", setup->observables[obs1].name, + setup->observables[obs2].name,setup->observables[obs3].name); + + x0 = x1 = x2 = 0; + update_caldac( setup, dac, x0 ); + usleep(100000); + + preobserve( setup, obs1); + new_sv_init(&sv1, setup->dev, setup->ad_subdev,chanspec1); + sv1.settling_time_ns = setup->settling_time_ns; + new_sv_measure( setup->dev, &sv1); + preobserve( setup, obs2); new_sv_init(&sv2, setup->dev, setup->ad_subdev,chanspec2); sv2.settling_time_ns = setup->settling_time_ns; new_sv_measure( setup->dev, &sv2); - y0 -= sv2.average; + + preobserve( setup, obs3); + new_sv_init(&sv3, setup->dev, setup->ad_subdev,chanspec3); + sv3.settling_time_ns = setup->settling_time_ns; + new_sv_measure( setup->dev, &sv3); + + y0 = sv1.average - sv2.average; y1 = y2 = y0; bit = 1; @@ -566,12 +659,18 @@ void cal_postgain_binary( calibration_setup_t *setup, int obs1, int obs2, int da new_sv_init(&sv1, setup->dev, setup->ad_subdev,chanspec1); sv1.settling_time_ns = setup->settling_time_ns; new_sv_measure( setup->dev, &sv1); - y2 = sv1.average; + preobserve( setup, obs2); new_sv_init(&sv2, setup->dev, setup->ad_subdev,chanspec2); sv2.settling_time_ns = setup->settling_time_ns; new_sv_measure( setup->dev, &sv2); - y2 -= sv2.average; + + preobserve( setup, obs3); + new_sv_init(&sv3, setup->dev, setup->ad_subdev,chanspec3); + sv3.settling_time_ns = setup->settling_time_ns; + new_sv_measure( setup->dev, &sv3); + + y2 = ( sv3.average - sv2.average ) / ( sv2.average - sv1.average ); DPRINT(3,"trying %d, result %g, target %g\n",x2,y2,target); @@ -588,6 +687,8 @@ void cal_postgain_binary( calibration_setup_t *setup, int obs1, int obs2, int da measure_observable( setup, obs1); preobserve( setup, obs2); measure_observable( setup, obs2); + preobserve( setup, obs3); + measure_observable( setup, obs3); } } @@ -602,6 +703,8 @@ void cal_postgain_binary( calibration_setup_t *setup, int obs1, int obs2, int da measure_observable( setup, obs1); preobserve( setup, obs2); measure_observable( setup, obs2); + preobserve( setup, obs3); + measure_observable( setup, obs3); } } diff --git a/comedi_calibrate/ni.c b/comedi_calibrate/ni.c index c76e654..a8c3ba9 100644 --- a/comedi_calibrate/ni.c +++ b/comedi_calibrate/ni.c @@ -2,21 +2,17 @@ A little auto-calibration utility, for boards that support it. - Right now, it only supports NI E series boards, - but it should be easily portable. + copyright (C) 1999,2000,2001,2002 by David Schleef + copyright (C) 2003 by Frank Mori Hess A few things need improvement here: - current system gets "close", but doesn't do any fine-tuning - - no pre/post gain discrimination for the - A/D zero offset. - should read (and use) the actual reference voltage value from eeprom - statistics would be nice, to show how good the calibration is. - doesn't check unipolar ranges - - "alternate calibrations" would be cool--to - accurately measure 0 in a unipolar range - more portable */ @@ -42,6 +38,7 @@ #include #include #include +#include #include "calib.h" @@ -53,6 +50,8 @@ struct board_struct{ int status; int (*cal)( calibration_setup_t *setup); void (*setup_observables)( calibration_setup_t *setup ); + int ref_eeprom_lsb; + int ref_eeprom_msb; }; static int ni_setup_board( calibration_setup_t *setup , const char *device_name ); @@ -83,28 +82,28 @@ static int cal_ni_daqcard_6062e(calibration_setup_t *setup); static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc); static struct board_struct boards[]={ - { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables }, - { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables }, - { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables }, - { "at-mio-16e-1", STATUS_SOME, cal_ni_at_mio_16e_1, ni_setup_observables }, - { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables }, - { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables }, - { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables }, - { "pci-6071e", STATUS_SOME, cal_ni_pci_6071e, ni_setup_observables }, - { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables }, - { "at-mio-16e-10", STATUS_GUESS, cal_ni_at_mio_16e_10, ni_setup_observables }, - { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables }, - { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables }, - { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables }, - { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables }, - { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables }, - { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables }, - { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables }, - { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables }, - { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x }, - { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x }, - { "DAQCard-6062E", STATUS_SOME, cal_ni_daqcard_6062e, ni_setup_observables }, - { "DAQCard-6024E", STATUS_UNKNOWN, NULL, ni_setup_observables }, + { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2, ni_setup_observables, -1, -1 }, + { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50, ni_setup_observables, -1, -1 }, + { "at-mio-16xe-50", STATUS_SOME, cal_ni_at_mio_16xe_50, ni_setup_observables, -1, -1 }, + { "at-mio-16e-1", STATUS_SOME, cal_ni_at_mio_16e_1, ni_setup_observables, -1, -1 }, + { "pci-mio-16e-1", STATUS_DONE, cal_ni_pci_mio_16e_1, ni_setup_observables, -1, -1 }, + { "pci-6025e", STATUS_SOME, cal_ni_pci_6025e, ni_setup_observables, -1, -1 }, + { "pci-6035e", STATUS_DONE, cal_ni_pci_6035e, ni_setup_observables, -1, -1 }, + { "pci-6071e", STATUS_SOME, cal_ni_pci_6071e, ni_setup_observables, -1, -1 }, + { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 }, + { "at-mio-16e-10", STATUS_GUESS, cal_ni_at_mio_16e_10, ni_setup_observables, -1, -1 }, + { "pci-mio-16xe-50", STATUS_SOME, cal_ni_pci_mio_16xe_50, ni_setup_observables, -1, -1 }, + { "pci-6023e", STATUS_DONE, cal_ni_pci_6023e, ni_setup_observables, -1, -1 }, + { "pci-mio-16xe-10", STATUS_DONE, cal_ni_pci_mio_16xe_10, ni_setup_observables, -1, -1 }, + { "pci-6052e", STATUS_DONE, cal_ni_pci_6052e, ni_setup_observables, -1, -1 }, + { "pci-6024e", STATUS_SOME, cal_ni_pci_6024e, ni_setup_observables, -1, -1 }, + { "pci-mio-16e-4", STATUS_SOME, cal_ni_pci_mio_16e_4, ni_setup_observables, -1, -1 }, + { "pci-6032e", STATUS_DONE, cal_ni_pci_6032e, ni_setup_observables, -1, -1 }, + { "DAQCard-ai-16e-4", STATUS_DONE, cal_ni_daqcard_ai_16e_4, ni_setup_observables, -1, -1 }, + { "pci-6110", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, -1, -1 }, + { "pci-6111", STATUS_DONE, cal_ni_pci_611x, ni_setup_observables_611x, -1, -1 }, + { "DAQCard-6062E", STATUS_DONE, cal_ni_daqcard_6062e, ni_setup_observables, -1, -1 }, + { "DAQCard-6024E", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 }, #if 0 // { "at-mio-16de-10", cal_ni_unknown }, { "at-mio-64e-3", cal_ni_16e_1 }, @@ -125,6 +124,7 @@ static struct board_struct boards[]={ }; #define n_boards (sizeof(boards)/sizeof(boards[0])) +static const int ni_num_observables = 12; enum observables{ ni_zero_offset_low = 0, ni_zero_offset_high, @@ -134,9 +134,26 @@ enum observables{ ni_unip_reference_low, ni_ao0_zero_offset, ni_ao0_reference, + ni_ao0_linearity, ni_ao1_zero_offset, ni_ao1_reference, + ni_ao1_linearity, }; +static inline unsigned int ni_ao_zero_offset( unsigned int channel ) +{ + if( channel ) return ni_ao1_zero_offset; + else return ni_ao0_zero_offset; +} +static inline unsigned int ni_ao_reference( unsigned int channel ) +{ + if( channel ) return ni_ao1_reference; + else return ni_ao0_reference; +} +static inline unsigned int ni_ao_linearity( unsigned int channel ) +{ + if( channel ) return ni_ao1_linearity; + else return ni_ao0_linearity; +} enum observables_611x{ ni_ao0_zero_offset_611x = 0, @@ -144,10 +161,10 @@ enum observables_611x{ ni_ao1_zero_offset_611x = 2, ni_ao1_reference_611x = 3, }; -inline static int ni_zero_offset_611x( int channel ) { +static inline unsigned int ni_zero_offset_611x( unsigned int channel ) { return 4 + 2 * channel; }; -inline static int ni_reference_611x( int channel ) { +static inline unsigned int ni_reference_611x( unsigned int channel ) { return 5 + 2 * channel; }; @@ -161,6 +178,16 @@ enum reference_sources { REF_DAC0_CALSRC = 6, REF_DAC1_CALSRC = 7, }; +static inline unsigned int REF_DAC_GND( unsigned int channel ) +{ + if( channel ) return REF_DAC1_GND; + else return REF_DAC0_GND; +} +static inline unsigned int REF_DAC_CALSRC( unsigned int channel ) +{ + if( channel ) return REF_DAC1_CALSRC; + else return REF_DAC0_CALSRC; +} int ni_setup( calibration_setup_t *setup , const char *device_name ) { @@ -211,7 +238,7 @@ static void ni_setup_observables( calibration_setup_t *setup ) tmpl.n = 1; tmpl.subdev = setup->ad_subdev; - setup->n_observables = 10; + setup->n_observables = ni_num_observables; /* 0 offset, low gain */ o = setup->observables + ni_zero_offset_low; @@ -274,65 +301,57 @@ static void ni_setup_observables( calibration_setup_t *setup ) if(setup->da_subdev>=0){ comedi_insn po_tmpl; + unsigned int channel; memset(&po_tmpl,0,sizeof(po_tmpl)); po_tmpl.insn = INSN_WRITE; po_tmpl.n = 1; po_tmpl.subdev = setup->da_subdev; - /* ao 0, zero offset */ - o = setup->observables + ni_ao0_zero_offset; - o->name = "ao 0, zero offset, low gain"; - o->preobserve_insn = po_tmpl; - o->preobserve_insn.chanspec = CR_PACK(0,0,0); - o->preobserve_insn.data = o->preobserve_data; - o->observe_insn = tmpl; - o->observe_insn.chanspec = - CR_PACK(REF_DAC0_GND,bipolar_lowgain,AREF_OTHER) - | CR_ALT_SOURCE | CR_ALT_FILTER; - o->reference_source = REF_DAC0_GND; - set_target( setup, ni_ao0_zero_offset,0.0); - - /* ao 0, gain */ - o = setup->observables + ni_ao0_reference; - o->name = "ao 0, reference voltage, low gain"; - o->preobserve_insn = po_tmpl; - o->preobserve_insn.chanspec = CR_PACK(0,0,0); - o->preobserve_insn.data = o->preobserve_data; - o->observe_insn = tmpl; - o->observe_insn.chanspec = - CR_PACK(REF_DAC0_CALSRC,bipolar_lowgain,AREF_OTHER) - | CR_ALT_SOURCE | CR_ALT_FILTER; - o->reference_source = REF_DAC0_CALSRC; - set_target( setup, ni_ao0_reference,5.0); - o->target -= voltage_reference; - - /* ao 1, zero offset */ - o = setup->observables + ni_ao1_zero_offset; - o->name = "ao 1, zero offset, low gain"; - o->preobserve_insn = po_tmpl; - o->preobserve_insn.chanspec = CR_PACK(1,0,0); - o->preobserve_insn.data = o->preobserve_data; - o->observe_insn = tmpl; - o->observe_insn.chanspec = - CR_PACK(REF_DAC1_GND,bipolar_lowgain,AREF_OTHER) - | CR_ALT_SOURCE | CR_ALT_FILTER; - o->reference_source = REF_DAC1_GND; - set_target( setup, ni_ao1_zero_offset,0.0); - - /* ao 1, gain */ - o = setup->observables + ni_ao1_reference; - o->name = "ao 1, reference voltage, low gain"; - o->preobserve_insn = po_tmpl; - o->preobserve_insn.chanspec = CR_PACK(1,0,0); - o->preobserve_insn.data = o->preobserve_data; - o->observe_insn = tmpl; - o->observe_insn.chanspec = - CR_PACK(REF_DAC1_CALSRC,bipolar_lowgain,AREF_OTHER) - | CR_ALT_SOURCE | CR_ALT_FILTER; - o->reference_source = REF_DAC1_CALSRC; - set_target( setup, ni_ao1_reference,5.0); - o->target -= voltage_reference; + for( channel = 0; channel < 2; channel++ ) + { + /* ao zero offset */ + o = setup->observables + ni_ao_zero_offset( channel ); + assert( o->name == NULL ); + asprintf( &o->name, "ao %i, zero offset, low gain", channel ); + o->preobserve_insn = po_tmpl; + o->preobserve_insn.chanspec = CR_PACK(channel,0,0); + o->preobserve_insn.data = o->preobserve_data; + o->observe_insn = tmpl; + o->observe_insn.chanspec = + CR_PACK(REF_DAC_GND( channel ),bipolar_lowgain,AREF_OTHER) + | CR_ALT_SOURCE | CR_ALT_FILTER; + o->reference_source = REF_DAC_GND( channel ); + set_target( setup, ni_ao_zero_offset( channel ),0.0); + + /* ao gain */ + o = setup->observables + ni_ao_reference( channel ); + assert( o->name == NULL ); + asprintf( &o->name, "ao %i, refernce voltage, low gain", channel ); + o->preobserve_insn = po_tmpl; + o->preobserve_insn.chanspec = CR_PACK(channel,0,0); + o->preobserve_insn.data = o->preobserve_data; + o->observe_insn = tmpl; + o->observe_insn.chanspec = + CR_PACK(REF_DAC_GND( channel ),bipolar_lowgain,AREF_OTHER) + | CR_ALT_SOURCE | CR_ALT_FILTER; + o->reference_source = REF_DAC_GND( channel ); + set_target( setup, ni_ao_reference( channel ),5.0); + + /* ao linearity, negative */ + o = setup->observables + ni_ao_linearity( channel ); + assert( o->name == NULL ); + asprintf( &o->name, "ao %i, linearity (negative), low gain", channel ); + o->preobserve_insn = po_tmpl; + o->preobserve_insn.chanspec = CR_PACK(channel,0,0); + o->preobserve_insn.data = o->preobserve_data; + o->observe_insn = tmpl; + o->observe_insn.chanspec = + CR_PACK(REF_DAC_GND( channel ),bipolar_lowgain,AREF_OTHER) + | CR_ALT_SOURCE | CR_ALT_FILTER; + o->reference_source = REF_DAC_GND( channel ); + set_target( setup, ni_ao_linearity( channel ),-5.0); + } } } @@ -840,24 +859,89 @@ static int cal_ni_pci_611x( calibration_setup_t *setup ) return 0; } +enum caldacs_dc6062e +{ + DAC1_LINEARITY_DC6062E = 1, /* not sure exactly what this does */ + ADC_GAIN_DC6062E = 2, /* couples strongly to offset in bipolar ranges */ + ADC_POSTGAIN_OFFSET_DC6062E = 4, + DAC1_GAIN_DC6062E = 5, + DAC0_OFFSET_DC6062E = 6, + ADC_UNIPOLAR_OFFSET_DC6062E = 7, + ADC_PREGAIN_OFFSET_DC6062E = 8, + DAC1_OFFSET_DC6062E = 9, + DAC0_LINEARITY_DC6062E = 10, + DAC0_GAIN_DC6062E = 11, +}; +static inline unsigned int DAC_OFFSET_DC6062E( unsigned int channel ) +{ + if( channel ) return DAC1_OFFSET_DC6062E; + else return DAC0_OFFSET_DC6062E; +} +static inline unsigned int DAC_GAIN_DC6062E( unsigned int channel ) +{ + if( channel ) return DAC1_GAIN_DC6062E; + else return DAC0_GAIN_DC6062E; +} +static inline unsigned int DAC_LINEARITY_DC6062E( unsigned int channel ) +{ + if( channel ) return DAC1_LINEARITY_DC6062E; + else return DAC0_LINEARITY_DC6062E; +} + +static void prep_adc_caldacs_dc6062e( calibration_setup_t *setup ) +{ + int retval; + + if( setup->do_reset ) + { + reset_caldac( setup, ADC_PREGAIN_OFFSET_DC6062E ); + reset_caldac( setup, ADC_POSTGAIN_OFFSET_DC6062E ); + reset_caldac( setup, ADC_GAIN_DC6062E ); + reset_caldac( setup, ADC_PREGAIN_OFFSET_DC6062E ); + }else + { + retval = comedi_apply_calibration( setup->dev, setup->ad_subdev, + 0, 0, AREF_GROUND, setup->cal_save_file_path); + if( retval < 0 ) + { + DPRINT( 0, "Failed to apply existing calibration, reseting adc caldacs.\n" ); + reset_caldac( setup, ADC_PREGAIN_OFFSET_DC6062E ); + reset_caldac( setup, ADC_POSTGAIN_OFFSET_DC6062E ); + reset_caldac( setup, ADC_GAIN_DC6062E ); + reset_caldac( setup, ADC_PREGAIN_OFFSET_DC6062E ); + } + } +} + +static void prep_dac_caldacs_dc6062e( calibration_setup_t *setup, + unsigned int channel ) +{ + int retval; + + if( setup->do_reset ) + { + reset_caldac( setup, DAC_OFFSET_DC6062E( channel ) ); + reset_caldac( setup, DAC_GAIN_DC6062E( channel ) ); + reset_caldac( setup, DAC_LINEARITY_DC6062E( channel ) ); + }else + { + retval = comedi_apply_calibration( setup->dev, setup->da_subdev, + channel, 0, AREF_GROUND, setup->cal_save_file_path); + if( retval < 0 ) + { + DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" ); + reset_caldac( setup, DAC_OFFSET_DC6062E( channel ) ); + reset_caldac( setup, DAC_GAIN_DC6062E( channel ) ); + reset_caldac( setup, DAC_LINEARITY_DC6062E( channel ) ); + } + } +} + static int cal_ni_daqcard_6062e( calibration_setup_t *setup ) { saved_calibration_t saved_cals[ 3 ], *current_cal; static const int num_calibrations = sizeof( saved_cals ) / sizeof( saved_cals[0] ); int i, retval; - enum caldacs - { - DAC1_LINEARITY = 1, /* not sure exactly what this does */ - ADC_GAIN = 2, /* couples strongly to offset */ - ADC_POSTGAIN_OFFSET = 4, - DAC1_GAIN = 5, - DAC0_OFFSET = 6, - ADC_UNIPOLAR_OFFSET = 7, - ADC_PREGAIN_OFFSET = 8, - DAC1_OFFSET = 9, - DAC0_LINEARITY = 10, /* not sure exactly what this does */ - DAC0_GAIN = 11, - }; comedi_set_global_oor_behavior( COMEDI_OOR_NUMBER ); @@ -865,45 +949,47 @@ static int cal_ni_daqcard_6062e( calibration_setup_t *setup ) memset( saved_cals, 0, sizeof( saved_cals ) ); - cal_postgain_binary( setup, ni_zero_offset_low, ni_reference_low, ADC_GAIN ); - cal_postgain_binary( setup, ni_zero_offset_low, ni_zero_offset_high, ADC_POSTGAIN_OFFSET ); - cal_binary( setup, ni_zero_offset_high, ADC_PREGAIN_OFFSET ); - cal_binary( setup, ni_unip_zero_offset_high, ADC_UNIPOLAR_OFFSET ); + prep_adc_caldacs_dc6062e( setup ); + + cal_postgain_binary( setup, ni_zero_offset_low, ni_reference_low, ADC_GAIN_DC6062E ); + cal_postgain_binary( setup, ni_zero_offset_low, ni_zero_offset_high, + ADC_POSTGAIN_OFFSET_DC6062E ); + cal_binary( setup, ni_zero_offset_high, ADC_PREGAIN_OFFSET_DC6062E ); + cal_binary( setup, ni_unip_zero_offset_high, ADC_UNIPOLAR_OFFSET_DC6062E ); current_cal->subdevice = setup->ad_subdev; - sc_push_caldac( current_cal, setup->caldacs[ ADC_PREGAIN_OFFSET ] ); - sc_push_caldac( current_cal, setup->caldacs[ ADC_GAIN ] ); - sc_push_caldac( current_cal, setup->caldacs[ ADC_POSTGAIN_OFFSET ] ); - sc_push_caldac( current_cal, setup->caldacs[ ADC_UNIPOLAR_OFFSET ] ); + sc_push_caldac( current_cal, setup->caldacs[ ADC_PREGAIN_OFFSET_DC6062E ] ); + sc_push_caldac( current_cal, setup->caldacs[ ADC_GAIN_DC6062E ] ); + sc_push_caldac( current_cal, setup->caldacs[ ADC_POSTGAIN_OFFSET_DC6062E ] ); + sc_push_caldac( current_cal, setup->caldacs[ ADC_UNIPOLAR_OFFSET_DC6062E ] ); sc_push_channel( current_cal, SC_ALL_CHANNELS ); sc_push_range( current_cal, SC_ALL_RANGES ); sc_push_aref( current_cal, SC_ALL_AREFS ); current_cal++; - if(setup->do_output){ - cal_binary( setup, ni_ao0_zero_offset, DAC0_OFFSET ); - cal_binary( setup, ni_ao0_reference, DAC0_GAIN ); - - current_cal->subdevice = setup->da_subdev; - sc_push_caldac( current_cal, setup->caldacs[ DAC0_OFFSET ] ); - sc_push_caldac( current_cal, setup->caldacs[ DAC0_GAIN ] ); - sc_push_caldac( current_cal, setup->caldacs[ DAC0_LINEARITY ] ); - sc_push_channel( current_cal, 0 ); - sc_push_range( current_cal, SC_ALL_RANGES ); - sc_push_aref( current_cal, SC_ALL_AREFS ); - current_cal++; - - cal_binary( setup, ni_ao1_zero_offset, DAC1_OFFSET ); - cal_binary( setup, ni_ao1_reference, DAC1_GAIN ); - - current_cal->subdevice = setup->da_subdev; - sc_push_caldac( current_cal, setup->caldacs[ DAC1_OFFSET ] ); - sc_push_caldac( current_cal, setup->caldacs[ DAC1_GAIN ] ); - sc_push_caldac( current_cal, setup->caldacs[ DAC1_LINEARITY ] ); - sc_push_channel( current_cal, 1 ); - sc_push_range( current_cal, SC_ALL_RANGES ); - sc_push_aref( current_cal, SC_ALL_AREFS ); - current_cal++; + if(setup->do_output) + { + unsigned int channel; + + for( channel = 0; channel < 2; channel++ ) + { + prep_dac_caldacs_dc6062e( setup, channel ); + + cal_linearity_binary( setup, ni_ao_linearity( channel ), + ni_ao_zero_offset( channel ), ni_ao_reference( channel ), + DAC_LINEARITY_DC6062E( channel ) ); + cal_binary( setup, ni_ao_zero_offset( channel ), DAC_OFFSET_DC6062E( channel ) ); + cal_binary( setup, ni_ao_reference( channel ), DAC_GAIN_DC6062E( channel ) ); + + current_cal->subdevice = setup->da_subdev; + sc_push_caldac( current_cal, setup->caldacs[ DAC_OFFSET_DC6062E( channel ) ] ); + sc_push_caldac( current_cal, setup->caldacs[ DAC_GAIN_DC6062E( channel ) ] ); + sc_push_caldac( current_cal, setup->caldacs[ DAC_LINEARITY_DC6062E( channel ) ] ); + sc_push_channel( current_cal, channel ); + sc_push_range( current_cal, SC_ALL_RANGES ); + sc_push_aref( current_cal, SC_ALL_AREFS ); + current_cal++; + } } retval = write_calibration_file( setup, saved_cals, num_calibrations ); @@ -926,6 +1012,9 @@ static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_ uv = ( lsb & 0xff ) | ( ( msb << 8 ) & 0xff00 ); ref=5.000+1.0e-6*uv; printf("ref=%g\n",ref); + if( fabs( ref - 5.0 ) > 0.005 ) + printf( "WARNING: eeprom indicates reference is more than 5mV away\n" + "from 5V. Possible bad eeprom address?\n" ); return ref; } -- 2.26.2