From 49b521c21c8bad390b9c9876bf09802e9c9781ef Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Tue, 17 Jun 2003 23:57:49 +0000 Subject: [PATCH] make it loop through gain/offset calibrations until the readings are within specified tolerance of targets. --- comedi_calibrate/cal_common.c | 83 +++++++++++++++++++++-------- comedi_calibrate/calib.h | 7 +++ comedi_calibrate/cb.c | 13 ++--- comedi_calibrate/cb64.c | 5 ++ comedi_calibrate/comedi_calibrate.c | 34 ++++++++++++ 5 files changed, 114 insertions(+), 28 deletions(-) diff --git a/comedi_calibrate/cal_common.c b/comedi_calibrate/cal_common.c index 8a87777..611cb0f 100644 --- a/comedi_calibrate/cal_common.c +++ b/comedi_calibrate/cal_common.c @@ -17,10 +17,12 @@ * (at your option) any later version. * * * ***************************************************************************/ +#define _GNU_SOURCE #include "calib.h" #include #include +#include void generic_do_cal( calibration_setup_t *setup, comedi_calibration_setting_t *saved_cal, int observable, int caldac ) @@ -132,49 +134,84 @@ static void generic_prep_adc_for_dac( calibration_setup_t *setup, const generic_ adc_channel, adc_range, 0, calibration ); } +static int dac_cal_is_good( calibration_setup_t *setup, const generic_layout_t *layout, + unsigned int channel, unsigned int range ) +{ + if( fabs( fractional_offset( setup, setup->da_subdev, channel, range, + layout->dac_ground_observable( setup, channel, range ) ) ) > layout->dac_fractional_tolerance ) + return 0; + else if( fabs( fractional_offset( setup, setup->da_subdev, channel, range, + layout->dac_high_observable( setup, channel, range ) ) ) > layout->dac_fractional_tolerance ) + return 0; + + return 1; +} + static void generic_do_dac_channel( calibration_setup_t *setup, const generic_layout_t *layout , comedi_calibration_t *calibration, comedi_calibration_setting_t *current_cal, unsigned int channel, unsigned int range ) { + static const int max_iterations = 4; + int i; + generic_prep_adc_for_dac( setup, layout, calibration, layout->dac_ground_observable( setup, channel, range ) ); - 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_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 ), - layout->dac_offset_fine( channel ) ); - + for( i = 0; i < max_iterations; i++ ) + { + 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_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 ), + layout->dac_offset_fine( channel ) ); + if( dac_cal_is_good( setup, layout, channel, range ) ) break; + } + if( i == max_iterations ) + DPRINT(0, "WARNING: unable to calibrate dac channel %i, range %i to desired %g tolerance\n", + channel, range, layout->dac_fractional_tolerance ); current_cal->subdevice = setup->da_subdev; sc_push_channel( current_cal, channel ); sc_push_range( current_cal, range ); sc_push_aref( current_cal, SC_ALL_AREFS ); } +static int adc_cal_is_good( calibration_setup_t *setup, const generic_layout_t *layout, + unsigned int channel, unsigned int range ) +{ + if( fabs( fractional_offset( setup, setup->ad_subdev, channel, range, + layout->adc_ground_observable( setup, channel, range ) ) ) > layout->adc_fractional_tolerance ) + return 0; + else if( fabs( fractional_offset( setup, setup->ad_subdev, channel, range, + layout->adc_high_observable( setup, channel, range ) ) ) > layout->adc_fractional_tolerance ) + return 0; + + return 1; +} + static void generic_do_adc_channel( calibration_setup_t *setup, const generic_layout_t *layout, comedi_calibration_setting_t *current_cal, unsigned int channel, unsigned int range ) { - /* make sure unipolar ground observable isn't out-of-range before - * doing gain calibrations */ - if( is_unipolar( setup->dev, setup->ad_subdev, channel, range ) ) + static const int max_iterations = 4; + int i; + + for( i = 0; i < max_iterations; i++ ) { + generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ), + layout->adc_ground_observable( setup, channel, range ), layout->adc_gain( channel ) ); generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ), layout->adc_offset( channel ) ); + generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ), + layout->adc_ground_observable( setup, channel, range ), layout->adc_gain_fine( channel ) ); generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ), layout->adc_offset_fine( channel ) ); + if( adc_cal_is_good( setup, layout, channel, range ) ) break; } - generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ), - layout->adc_ground_observable( setup, channel, range ), layout->adc_gain( channel ) ); - generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ), - layout->adc_offset( channel ) ); - generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ), - layout->adc_ground_observable( setup, channel, range ), layout->adc_gain_fine( channel ) ); - generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ), - layout->adc_offset_fine( channel ) ); - + if( i == max_iterations ) + DPRINT(0, "WARNING: unable to calibrate adc channel %i, range %i to desired %g tolerance\n", + channel, range, layout->adc_fractional_tolerance ); current_cal->subdevice = setup->ad_subdev; sc_push_channel( current_cal, channel ); sc_push_range( current_cal, range ); @@ -395,5 +432,7 @@ void init_generic_layout( generic_layout_t *layout ) layout->adc_ground_observable = dummy_observable; layout->dac_high_observable = dummy_observable; layout->dac_ground_observable = dummy_observable; - layout->do_adc_unipolar_postgain = 1; + layout->adc_fractional_tolerance = INFINITY; + layout->adc_fractional_tolerance = INFINITY; + layout->do_adc_unipolar_postgain = 0; } diff --git a/comedi_calibrate/calib.h b/comedi_calibrate/calib.h index 6e76d84..7cc9e13 100644 --- a/comedi_calibrate/calib.h +++ b/comedi_calibrate/calib.h @@ -152,6 +152,11 @@ int is_bipolar( comedi_t *dev, unsigned int subdevice, int is_unipolar( comedi_t *dev, unsigned int subdevice, unsigned int channel, unsigned int range ); +double fractional_offset( calibration_setup_t *setup, int subdevice, + unsigned int channel, unsigned int range, int obs ); +double get_tolerance( calibration_setup_t *setup, int subdevice, + double num_bits ); + /* other */ void comedi_nanodelay(comedi_t *dev, unsigned int delay); @@ -251,6 +256,8 @@ typedef struct 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; + double dac_fractional_tolerance; unsigned do_adc_unipolar_postgain : 1; } generic_layout_t; void init_generic_layout( generic_layout_t *layout ); diff --git a/comedi_calibrate/cb.c b/comedi_calibrate/cb.c index 5e410be..0848367 100644 --- a/comedi_calibrate/cb.c +++ b/comedi_calibrate/cb.c @@ -64,11 +64,6 @@ static struct board_struct boards[]={ static const int num_boards = ( sizeof(boards) / sizeof(boards[0]) ); -enum observables_1602_16 { - OBS_0V_RANGE_10V_BIP_1602_16 = 0, - OBS_7V_RANGE_10V_BIP_1602_16, -}; - enum calibration_source_1xxx { CS_1XXX_GROUND = 0, @@ -140,8 +135,10 @@ static int setup_cb_pci_1602_16( calibration_setup_t *setup ) DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n" "for this calibration to work properly\n" ); } - + setup->sv_settling_time_ns = 10000000; + setup->sv_order = 12; retval = init_observables_1xxx( setup ); + if( retval < 0 ) return retval; setup_caldacs( setup, caldac_subdev ); setup_caldacs( setup, calpot_subdev ); @@ -424,6 +421,8 @@ static int cal_cb_pci_1xxx( calibration_setup_t *setup ) layout.adc_ground_observable = ai_ground_observable_1xxx; layout.dac_high_observable = ao_high_observable_1xxx; layout.dac_ground_observable = ao_ground_observable_1xxx; + layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 ); + layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 ); return generic_cal_by_range( setup, &layout ); } @@ -489,6 +488,8 @@ static int cal_cb_pci_1602_16( calibration_setup_t *setup ) layout.adc_ground_observable = ai_ground_observable_1xxx; layout.dac_high_observable = ao_high_observable_1xxx; layout.dac_ground_observable = ao_ground_observable_1xxx; + layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 ); + layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 ); /* The bipolar postgain calibration should be good for both * bipolar and unipolar ranges, so disable separate * unipolar postgain offset calibration (it will fail diff --git a/comedi_calibrate/cb64.c b/comedi_calibrate/cb64.c index 7ae3115..61b1123 100644 --- a/comedi_calibrate/cb64.c +++ b/comedi_calibrate/cb64.c @@ -763,6 +763,8 @@ static int cal_cb_pci_64xx( calibration_setup_t *setup ) layout.adc_ground_observable = ai_ground_observable_index_64xx; layout.dac_high_observable = ao_high_observable_index_64xx; layout.dac_ground_observable = ao_ground_observable_index_64xx; + layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 ); + layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 ); return generic_cal_by_range( setup, &layout ); } @@ -807,6 +809,8 @@ static int cal_cb_pci_60xx( calibration_setup_t *setup ) layout.adc_ground_observable = ai_ground_observable_index_60xx; layout.dac_high_observable = ao_high_observable_index_60xx; layout.dac_ground_observable = ao_ground_observable_index_60xx; + layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 ); + layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 ); return generic_cal_by_range( setup, &layout ); } @@ -828,6 +832,7 @@ static int cal_cb_pci_4020( calibration_setup_t *setup ) layout.adc_gain = adc_gain_4020; layout.adc_high_observable = ai_high_observable_index_4020; layout.adc_ground_observable = ai_low_observable_index_4020; + layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 ); return generic_cal_by_channel_and_range( setup, &layout ); } diff --git a/comedi_calibrate/comedi_calibrate.c b/comedi_calibrate/comedi_calibrate.c index 90b80e6..117dc44 100644 --- a/comedi_calibrate/comedi_calibrate.c +++ b/comedi_calibrate/comedi_calibrate.c @@ -1587,4 +1587,38 @@ double very_low_target( comedi_t *dev, unsigned int subdevice, return comedi_to_phys( 1, range_ptr, max_data ) / 2.0; } +double fractional_offset( calibration_setup_t *setup, int subdevice, + unsigned int channel, unsigned int range, int obs ) +{ + comedi_range *range_ptr; + double target = setup->observables[obs].target; + double reading; + unsigned int chanspec = setup->observables[obs].observe_insn.chanspec; + new_sv_t sv; + if( subdevice < 0 || obs < 0 ) return 0.0; + + range_ptr = comedi_get_range( setup->dev, subdevice, channel, range ); + assert( range_ptr != NULL ); + + comedi_set_global_oor_behavior( COMEDI_OOR_NUMBER ); + preobserve( setup, obs); + + my_sv_init( &sv, setup, setup->ad_subdev, chanspec ); + new_sv_measure( setup->dev, &sv ); + reading = sv.average; + + return ( reading - target ) / ( range_ptr->max - range_ptr->min ); +} + +double get_tolerance( calibration_setup_t *setup, int subdevice, + double num_bits ) +{ + int maxdata; + + if( subdevice < 0 ) return INFINITY; + + maxdata = comedi_get_maxdata( setup->dev, subdevice, 0 ); + assert( maxdata > 0 ); + return num_bits / maxdata; +} -- 2.26.2