From 9097a55736595f3e35ea7fefe28cc5f01bd5f6ab Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Sun, 15 Feb 2004 22:24:57 +0000 Subject: [PATCH] add support for 67xx boards. Doesn't work yet, due to unknown reference of internal calibration adc. On my board, it's input seems to be about 2% off from +-10V. --- comedi_calibrate/cal_common.c | 49 +++++++++ comedi_calibrate/calib.h | 10 +- comedi_calibrate/comedi_calibrate.c | 36 ++++--- comedi_calibrate/ni.c | 158 +++++++++++++++++++++++++++- 4 files changed, 232 insertions(+), 21 deletions(-) diff --git a/comedi_calibrate/cal_common.c b/comedi_calibrate/cal_common.c index b57f11a..7f99c7a 100644 --- a/comedi_calibrate/cal_common.c +++ b/comedi_calibrate/cal_common.c @@ -101,8 +101,10 @@ void generic_prep_dac_caldacs( calibration_setup_t *setup, { reset_caldac( setup, layout->dac_offset( channel ) ); reset_caldac( setup, layout->dac_gain( channel ) ); + reset_caldac( setup, layout->dac_linearity( channel ) ); reset_caldac( setup, layout->dac_offset_fine( channel ) ); reset_caldac( setup, layout->dac_gain_fine( channel ) ); + reset_caldac( setup, layout->dac_linearity_fine( channel ) ); }else { retval = comedi_apply_parsed_calibration( setup->dev, setup->da_subdev, @@ -112,8 +114,10 @@ void generic_prep_dac_caldacs( calibration_setup_t *setup, DPRINT( 0, "Failed to apply existing calibration, reseting dac caldacs.\n" ); reset_caldac( setup, layout->dac_offset( channel ) ); reset_caldac( setup, layout->dac_gain( channel ) ); + reset_caldac( setup, layout->dac_linearity( channel ) ); reset_caldac( setup, layout->dac_offset_fine( channel ) ); reset_caldac( setup, layout->dac_gain_fine( channel ) ); + reset_caldac( setup, layout->dac_linearity_fine( channel ) ); } } } @@ -161,10 +165,19 @@ static void generic_do_dac_channel( calibration_setup_t *setup, const generic_la for( i = 0; i < max_iterations; i++ ) { + generic_do_linearity(setup, current_cal, layout->dac_ground_observable( setup, channel, range ), + layout->dac_mid_observable( setup, channel, range ), + layout->dac_high_observable( setup, channel, range ), + layout->dac_linearity(channel)); generic_do_relative( setup, current_cal, layout->dac_high_observable( setup, channel, range ), layout->dac_ground_observable( setup, channel, range ),layout->dac_gain( channel ) ); generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ), layout->dac_offset( channel ) ); + + generic_do_linearity(setup, current_cal, layout->dac_ground_observable( setup, channel, range ), + layout->dac_mid_observable( setup, channel, range ), + layout->dac_high_observable( setup, channel, range ), + layout->dac_linearity_fine(channel)); generic_do_relative( setup, current_cal, layout->dac_high_observable( setup, channel, range ), layout->dac_ground_observable( setup, channel, range ), layout->dac_gain_fine( channel ) ); generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ), @@ -411,6 +424,39 @@ int generic_cal_by_range( calibration_setup_t *setup, return retval; } +int generic_cal_ao(calibration_setup_t *setup, + const generic_layout_t *layout ) +{ + int channel, range, num_ao_ranges, + num_ao_channels, retval; + comedi_calibration_setting_t *current_cal; + + + if(setup->da_subdev && setup->do_output) + { + assert( comedi_range_is_chan_specific( setup->dev, setup->da_subdev ) == 0 ); + + num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, 0 ); + if( num_ao_ranges < 0 ) return -1; + + num_ao_channels = comedi_get_n_channels( setup->dev, setup->da_subdev ); + if( num_ao_channels < 0 ) return -1; + }else + num_ao_ranges = num_ao_channels = 0; + for( channel = 0; channel < num_ao_channels; channel++ ) + { + for( range = 0; range < num_ao_ranges; range++ ) + { + current_cal = sc_alloc_calibration_setting( setup ); + generic_prep_dac_caldacs( setup, layout, channel, range ); + generic_do_dac_channel( setup, layout, setup->new_calibration, + current_cal, channel, range ); + } + } + retval = write_calibration_file( setup ); + return retval; +} + static int dummy_caldac( unsigned int channel ) { return -1; @@ -429,11 +475,14 @@ void init_generic_layout( generic_layout_t *layout ) layout->adc_postgain_offset = dummy_caldac; layout->dac_offset = dummy_caldac; layout->dac_offset_fine = dummy_caldac; + layout->dac_linearity = dummy_caldac; + layout->dac_linearity_fine = dummy_caldac; layout->dac_gain = dummy_caldac; layout->dac_gain_fine = dummy_caldac; layout->adc_high_observable = dummy_observable; layout->adc_ground_observable = dummy_observable; layout->dac_high_observable = dummy_observable; + layout->dac_mid_observable = dummy_observable; layout->dac_ground_observable = dummy_observable; layout->adc_fractional_tolerance = INFINITY; layout->adc_fractional_tolerance = INFINITY; diff --git a/comedi_calibrate/calib.h b/comedi_calibrate/calib.h index 23a10d2..fdd584f 100644 --- a/comedi_calibrate/calib.h +++ b/comedi_calibrate/calib.h @@ -51,9 +51,7 @@ typedef struct{ comedi_insn observe_insn; - //comedi_range *range; - //int maxdata; - lsampl_t reference_source; + int reference_source; double target; }observable; @@ -244,6 +242,8 @@ typedef struct int (*adc_postgain_offset)( unsigned int channel ); int (*adc_gain)( unsigned int channel ); int (*adc_gain_fine)( unsigned int channel ); + int (*dac_linearity)( unsigned int channel ); + int (*dac_linearity_fine)( unsigned int channel ); int (*dac_offset)( unsigned int channel ); int (*dac_offset_fine)( unsigned int channel ); int (*dac_gain)( unsigned int channel ); @@ -254,6 +254,8 @@ typedef struct unsigned int channel, unsigned int range ); int (*dac_high_observable)( const calibration_setup_t *setup, unsigned int channel, unsigned int range ); + int (*dac_mid_observable)( const calibration_setup_t *setup, + unsigned int channel, unsigned int range ); int (*dac_ground_observable)( const calibration_setup_t *setup, unsigned int channel, unsigned int range ); double adc_fractional_tolerance; @@ -265,6 +267,8 @@ int generic_cal_by_channel_and_range( calibration_setup_t *setup, const generic_layout_t *layout ); int generic_cal_by_range( calibration_setup_t *setup, const generic_layout_t *layout ); +int generic_cal_ao(calibration_setup_t *setup, + const generic_layout_t *layout ); void generic_do_cal( calibration_setup_t *setup, comedi_calibration_setting_t *saved_cal, int observable, int caldac ); void generic_do_relative( calibration_setup_t *setup, diff --git a/comedi_calibrate/comedi_calibrate.c b/comedi_calibrate/comedi_calibrate.c index 8ef2b99..54cf1e1 100644 --- a/comedi_calibrate/comedi_calibrate.c +++ b/comedi_calibrate/comedi_calibrate.c @@ -319,7 +319,7 @@ ok: return retval; } -void set_target( calibration_setup_t *setup, int obs,double target) +void set_target( calibration_setup_t *setup, int obs, double target) { comedi_range *range; lsampl_t maxdata, data; @@ -397,19 +397,22 @@ int preobserve( calibration_setup_t *setup, int obs) lsampl_t ref_data[ 2 ]; // setup reference source - memset( &reference_source_config, 0, sizeof(reference_source_config) ); - reference_source_config.insn = INSN_CONFIG; - reference_source_config.n = 2; - reference_source_config.subdev = setup->ad_subdev; - reference_source_config.data = ref_data; - reference_source_config.data[ 0 ] = INSN_CONFIG_ALT_SOURCE; - reference_source_config.data[ 1 ] = setup->observables[obs].reference_source; - - retval = comedi_do_insn( setup->dev, &reference_source_config ); - /* ignore errors for now since older ni driver doesn't - * support reference config insn */ - if( retval < 0 ) - perror("preobserve() ignoring reference config error" ); + if(setup->observables[obs].reference_source >= 0) + { + memset( &reference_source_config, 0, sizeof(reference_source_config) ); + reference_source_config.insn = INSN_CONFIG; + reference_source_config.n = 2; + reference_source_config.subdev = setup->ad_subdev; + reference_source_config.data = ref_data; + reference_source_config.data[ 0 ] = INSN_CONFIG_ALT_SOURCE; + reference_source_config.data[ 1 ] = setup->observables[obs].reference_source; + + retval = comedi_do_insn( setup->dev, &reference_source_config ); + /* ignore errors for now since older ni driver doesn't + * support reference config insn */ + if( retval < 0 ) + perror("preobserve() ignoring reference config error" ); + } retval = 0; if( setup->observables[obs].preobserve_insn.n != 0){ @@ -914,9 +917,10 @@ void setup_caldacs( calibration_setup_t *setup, int caldac_subdev ) } // XXX check subdevice type is really calibration - // XXX check we dont exceed max number of allowable caldacs n_chan = comedi_get_n_channels( setup->dev, caldac_subdev ); + assert(n_chan >= 0); + assert(setup->n_caldacs + n_chan < N_CALDACS); for(i = 0; i < n_chan; i++){ setup->caldacs[ setup->n_caldacs + i ].subdev = caldac_subdev; @@ -1461,7 +1465,7 @@ int linear_fit_monotonic(linear_fit_t *l) l->sxx+=x*x; } sxp=l->sxx-l->sx*l->sx/l->s1; - + l->ave_x=l->sx/l->s1; l->ave_y=l->sy/l->s1; l->slope=(l->s1*l->sxy-l->sx*l->sy)/(l->s1*l->sxx-l->sx*l->sx); diff --git a/comedi_calibrate/ni.c b/comedi_calibrate/ni.c index 496894f..d8f74f4 100644 --- a/comedi_calibrate/ni.c +++ b/comedi_calibrate/ni.c @@ -47,6 +47,7 @@ struct board_struct{ static int ni_setup_board( calibration_setup_t *setup , const char *device_name ); static void ni_setup_observables( calibration_setup_t *setup ); static void ni_setup_observables_611x( calibration_setup_t *setup ); +static void ni67xx_setup_observables( calibration_setup_t *setup ); static int cal_ni_at_mio_16e_2(calibration_setup_t *setup); static int cal_ni_daqcard_ai_16xe_50(calibration_setup_t *setup); @@ -70,6 +71,7 @@ static int cal_ni_pci_611x(calibration_setup_t *setup); static int cal_ni_pci_mio_16e_4(calibration_setup_t *setup); static int cal_ni_daqcard_6062e(calibration_setup_t *setup); static int cal_ni_daqcard_6024e(calibration_setup_t *setup); +static int cal_ni_pci_6711(calibration_setup_t *setup); static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_loc); @@ -110,10 +112,16 @@ static struct board_struct boards[]={ { "pxi-6052e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 }, { "pxi-6070e", STATUS_UNKNOWN, NULL, ni_setup_observables, -1, -1 }, { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e, ni_setup_observables, -1, -1 }, + { "pci-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pci-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pci-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pci-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pxi-6711", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pxi-6713", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pxi-6731", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, + { "pxi-6733", STATUS_GUESS, cal_ni_pci_6711, ni67xx_setup_observables, -1, -1}, #if 0 { "at-mio-64e-3", cal_ni_16e_1 }, - { "pci-6711", cal_ni_unknown }, - { "pci-6713", cal_ni_unknown }, #endif }; #define n_boards (sizeof(boards)/sizeof(boards[0])) @@ -1362,3 +1370,149 @@ static double ni_get_reference( calibration_setup_t *setup, int lsb_loc,int msb_ return ref; } +/**************** + NI 671x and 673x support + **************/ + +static const int channels_per_ad8804 = 16; + +static inline int ni67xx_ao_gain_caldac(unsigned int ao_channel) +{ + int ad8804_gain_channels[4] = {8, 2, 11, 5}; + int caldac_channel = ad8804_gain_channels[ao_channel % 4]; + int caldac_index = ao_channel / 4; + /* just guessing that second ad8804 is works for ao channels 4-7 + * the same as the first ad8804 works for ao channels 0-3 */ + return caldac_index * channels_per_ad8804 + caldac_channel; +} +static inline int ni67xx_ao_linearity_caldac(unsigned int ao_channel) +{ + int ad8804_linearity_channels[4] = {4, 10, 1, 0}; + int caldac_channel = ad8804_linearity_channels[ao_channel % 4]; + int caldac_index = ao_channel / 4; + + return caldac_index * channels_per_ad8804 + caldac_channel; +} +static inline int ni67xx_ao_offset_caldac(unsigned int ao_channel) +{ + int ad8804_offset_channels[4] = {7, 6, 9, 3}; + int caldac_channel = ad8804_offset_channels[ao_channel % 4]; + int caldac_index = ao_channel / 4; + + return caldac_index * channels_per_ad8804 + caldac_channel; +} + +static int ni67xx_ao_ground_observable_index( const calibration_setup_t *setup, + unsigned int channel, unsigned int ao_range ) +{ + return 3 * channel; +} + +static int ni67xx_ao_mid_observable_index( const calibration_setup_t *setup, + unsigned int channel, unsigned int ao_range ) +{ + return 3 * channel + 1; +} + +static int ni67xx_ao_high_observable_index( const calibration_setup_t *setup, + unsigned int channel, unsigned int ao_range ) +{ + return 3 * channel + 2; +} + +/* calibration adc uses RANGE_UNKNOWN, so it will return a value from + 0.0 to 1.0 instead of a voltage, so we need to renormalize. */ +void ni67xx_set_target( calibration_setup_t *setup, int obs,double target) +{ + static const double reference = 5.0; + + set_target(setup, obs, target); + /* calibration adc is roughly +=10V range, and inverted */ + setup->observables[obs].target *= -1.0 / (reference * 4.0); + setup->observables[obs].target += 0.5; +} + +static void ni67xx_setup_observables( calibration_setup_t *setup ) +{ + comedi_insn tmpl, po_tmpl; + observable *o; + int num_ao_channels; + int i; + + /* calibration adc is very slow (15HZ) but accurate, so only sample a few times */ + setup->sv_order = 1; + + num_ao_channels = comedi_get_n_channels(setup->dev, setup->da_subdev); + assert(num_ao_channels >= 0); + + memset( &tmpl, 0, sizeof(tmpl) ); + tmpl.insn = INSN_READ; + tmpl.n = 1; + tmpl.subdev = setup->ad_subdev; + + memset( &po_tmpl, 0, sizeof(po_tmpl) ); + po_tmpl.insn = INSN_WRITE; + po_tmpl.n = 1; + po_tmpl.subdev = setup->da_subdev; + + setup->n_observables = 0; + + for(i = 0; i < num_ao_channels; i++) + { + o = setup->observables + ni67xx_ao_ground_observable_index( setup, + i, 0); + o->reference_source = -1; + assert( o->name == NULL ); + asprintf(&o->name, "dac%i ground, ground referenced", i); + o->preobserve_insn = po_tmpl; + o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND); + o->preobserve_insn.data = o->preobserve_data; + o->observe_insn = tmpl; + o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND); + ni67xx_set_target(setup, ni67xx_ao_ground_observable_index(setup, i, 0), 0.0); + setup->n_observables++; + + o = setup->observables + ni67xx_ao_mid_observable_index( setup, + i, 0); + o->reference_source = -1; + assert( o->name == NULL ); + asprintf(&o->name, "dac%i mid, ground referenced", i); + o->preobserve_insn = po_tmpl; + o->preobserve_insn.chanspec = CR_PACK(i, 0, AREF_GROUND); + o->preobserve_insn.data = o->preobserve_data; + o->observe_insn = tmpl; + o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND); + ni67xx_set_target(setup, ni67xx_ao_mid_observable_index(setup, i, 0), 4.0); + setup->n_observables++; + + o = setup->observables + ni67xx_ao_high_observable_index( setup, i, 0); + o->reference_source = -1; + assert( o->name == NULL ); + asprintf(&o->name, "dac%i high, ground referenced", i); + o->preobserve_insn = po_tmpl; + o->preobserve_insn.chanspec = CR_PACK( i, 0, AREF_GROUND ); + o->preobserve_insn.data = o->preobserve_data; + o->observe_insn = tmpl; + o->observe_insn.chanspec = CR_PACK(i, 0, AREF_GROUND); + ni67xx_set_target(setup, ni67xx_ao_high_observable_index(setup, i, 0), 8.0); + setup->n_observables++; + } + + return; +} + +static int cal_ni_pci_6711(calibration_setup_t *setup) +{ + generic_layout_t layout; + + init_generic_layout( &layout ); + layout.dac_gain = ni67xx_ao_gain_caldac; + layout.dac_linearity = ni67xx_ao_linearity_caldac; + layout.dac_offset = ni67xx_ao_offset_caldac; + layout.dac_high_observable = ni67xx_ao_high_observable_index; + layout.dac_mid_observable = ni67xx_ao_mid_observable_index; + layout.dac_ground_observable = ni67xx_ao_ground_observable_index; + layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1.0 ); + return generic_cal_ao(setup, &layout); +} + -- 2.26.2