This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F47187 / Accuracy errors with SD16_A using A5 and A7 channels for calibration

We are using SD16_A to mesure energy but we have a problem to calibrate SD16_A channels and to have accurate measurements.


Calibration procedure used:

We switch all extenal channels of SD16_A (A0-A4) on the input A7 to calculate the offset of each channel
We use A0 channel connected to an external voltage reference to calculate the gain of this channel.
We use A0 channel calibrated previously to calculate the internal voltage of the input A5.
We switch successively all the other channels (A1-A4) on the A5 input to calculate the gain of each channel.
So we obtain the offset and the gain of each channel of S16_A.

However when we apply the same voltage in input of each channel, we don't have the same values after gain and offset correction previously calculated.
Here is an example of our errors:
 

Input value: 0V:
channel 1: 0.06 mV
channel 2: 0 mV
channel 3: -0.01 mV
channel 4: -0.14 mV

Input value 100mV:
channel 1: 99.83 mV
channel 2: 99.73 mV
channel 3: 99.70 mV
channel 4: 99.66 mV

We have an error both on the offset and the gain. Is threre accuracy problem with A5 and A7 input to calibrate correctly SD16_A ?

Please help us. Thanks.
  • Are you waiting until the 4th conversion after switching channels?  This is necessary to allow the digital filter to settle.  Using conversions 1 - 3 might give you inaccurate measurements.  Provide a code sample so that we can see SD16_A initialization and your calibration function.

    Cheers,

    Clark

  • Thank you for you answer.
     
    Yes I am waiting 4 samples after switching channels. My configuration of the register SD16INCTL if the following:
    SD16INTDLY =  00  : Fourth sample causes interrupt
     
    I give you a sample of my code:
     
    #define SD16CCTL_DC_VOLTAGE       SD16CCTL0
    #define SD16INCTL_DC_VOLTAGE      SD16INCTL0
    #define SD16PRE_DC_VOLTAGE        SD16PRE0
    #define SD16MEM_DC_VOLTAGE        SD16MEM0
    #define SD16_DC_VOLTAGE 0
     
    #define SD16CCTL_CTRL_DERIV    SD16CCTL4
    #define SD16INCTL_CTRL_DERIV   SD16INCTL4
    #define SD16PRE_CTRL_DERIV     SD16PRE4
    #define SD16MEM_CTRL_DERIV     SD16MEM4
    #define SD16_CTRL_DERIV 4
     
     
    SD16_A initialization:
     
    void init_analog_front_end_calibration(int num_chan_calib, int num_analog_input)
    {
        int i;
     
        SD16CCTL_DC_VOLTAGE &= ~SD16SC;
        SD16CCTL_DC_CURRENT &= ~SD16SC;
        SD16CCTL_AC_VOLTAGE &= ~SD16SC;
        SD16CCTL_AC_CURRENT &= ~SD16SC;
        SD16CCTL_CTRL_DERIV &= ~SD16SC;
     
        SD16CTL = SD16XDIV_2;  /* Divide by 16 => SD16_A clock: 1 MHz */

        /* switching channel 4 to A5 */
        /* switching others channels to A0 */
     
        SD16INCTL_CTRL_DERIV = SD16INCH_5 | CTRL_DERIV_GAIN;        /* Set gain for channel 4 */
        SD16INCTL_DC_VOLTAGE = DC_VOLTAGE_GAIN;        /* Set gain for channel 0 */
        SD16INCTL_DC_CURRENT = DC_CURRENT_GAIN;        /* Set gain for channel 1 */
        SD16INCTL_AC_VOLTAGE = AC_VOLTAGE_GAIN;        /* Set gain for channel 2 */
        SD16INCTL_AC_CURRENT = AC_CURRENT_GAIN;        /* Set gain for channel 3 */

       
        /* switching num_chan_calib to num analog_input*/

        switch(num_chan_calib)
        {
          case SD16_CTRL_DERIV:
          /* Configure analog front-end channel 4 */
          SD16INCTL_CTRL_DERIV = num_analog_input | CTRL_DERIV_GAIN;
          break;
     
          case SD16_DC_VOLTAGE:
          /* Configure analog front-end channel 0 - Voltage DC */
          SD16INCTL_DC_VOLTAGE = num_analog_input | DC_VOLTAGE_GAIN; 
          break;
     
          case SD16_DC_CURRENT:
          /* Configure analog front-end channel 1 - Current DC */
          SD16INCTL_DC_CURRENT = num_analog_input | DC_CURRENT_GAIN;

          break;
     
        case SD16_AC_VOLTAGE:
          /* Configure analog front-end channel 2 - Voltage AC */
          SD16INCTL_AC_VOLTAGE = num_analog_input | AC_VOLTAGE_GAIN;
          break;
     
        case SD16_AC_CURRENT:
          /* Configure analog front-end channel 3 - Current DC */
          SD16INCTL_AC_CURRENT = num_analog_input | AC_CURRENT_GAIN;
          break;
        }
     
        /* Configure analog front-end channel 0 - Voltage DC */
        SD16CCTL_DC_VOLTAGE = SD16OSR_256 | SD16DF | SD16GRP | SD16IE;       /* Set oversampling ratio to 256 (default) */
        SD16PRE_DC_VOLTAGE = 0;
     
        /* Configure analog front-end channel 1 - Current DC */
        SD16CCTL_DC_CURRENT = SD16OSR_256 | SD16DF | SD16GRP | SD16IE;       /* Set oversampling ratio to 256 (default) */
        SD16PRE_DC_CURRENT = 0;
     
        /* Configure analog front-end channel 2 - Voltage AC */
        SD16CCTL_AC_VOLTAGE = SD16OSR_256 | SD16DF | SD16GRP | SD16IE;       /* Set oversampling ratio to 256 (default) */
        SD16PRE_AC_VOLTAGE = 0;
     
        /* Configure analog front-end channel 3 - Current DC */
        SD16CCTL_AC_CURRENT = SD16OSR_256 | SD16DF | SD16GRP | SD16IE;       /* Set oversampling ratio to 256 (default) */
        SD16PRE_AC_CURRENT = 0;
     
        /* Configure analog front-end channel 4 */
        SD16CCTL_CTRL_DERIV = SD16OSR_256 | SD16DF | SD16IE;       /* Set oversampling ratio to 256 (default) */
        SD16PRE_CTRL_DERIV = 0;
     
        SD16CCTL_DC_VOLTAGE |= SD16SC;
        SD16CCTL_DC_CURRENT |= SD16SC;
        SD16CCTL_AC_VOLTAGE |= SD16SC;
        SD16CCTL_AC_CURRENT |= SD16SC;
        SD16CCTL_CTRL_DERIV |= SD16SC;

    }
     
    Calibration function (called by SD16_A interruption)
     
        if(calibration_mode != 0)
        {
          if((SD16CCTL_CTRL_DERIV & SD16IFG) && (SD16CCTL_DC_VOLTAGE & SD16IFG) && (SD16CCTL_DC_CURRENT & SD16IFG) && (SD16CCTL_AC_VOLTAGE & SD16IFG) && (SD16CCTL_AC_CURRENT & SD16IFG))
          {
            if (calibration_mode == 1)
            {
              /* offset calculation of all channels (0V on all input channels) */
              /* all input channels have been switched on A7*/
              memo_vdc_calib[nb_value_memo] = - SD16MEM_DC_VOLTAGE;
              memo_idc_calib[nb_value_memo] =  - SD16MEM_DC_CURRENT;
              memo_vac_calib[nb_value_memo] = - SD16MEM_AC_VOLTAGE;
              memo_iac_calib[nb_value_memo] = - SD16MEM_AC_CURRENT;
              memo_deriv_calib[nb_value_memo] = - SD16MEM_CTRL_DERIV;
              nb_value_memo++;
              /* average on 16 points */
              if(nb_value_memo >= NB_PT_CALIB)
              {
                nb_value_memo = 0;
                dc_voltage_offset = average(memo_vdc_calib);
                dc_current_offset = average(memo_idc_calib);
                ac_voltage_offset = average(memo_vac_calib);
                ac_current_offset = average(memo_iac_calib);
                ctrl_deriv_offset = average(memo_deriv_calib);
     
                /* swithing channel 4 to A0 (externale Vref) to calculate its gain */
                init_analog_front_end_calibration(SD16_CTRL_DERIV);
                calibration_mode = 2;
              }
            }
            else
            {
              if(calibration_mode == 2)
              {
                /* gain calculation of channel 4 */
                /* channel 4 is switched to A0 (external Vref) */
                memo_sample[nb_value_memo] = SD16MEM_CTRL_DERIV;
                nb_value_memo++;
                if(nb_value_memo >= NB_PT_CALIB)
                {
                  nb_value_memo = 0;
                  V_sample = average(memo_sample);
     
                  ctrl_deriv_gain = V_REF_CALIBRATION;
                  ctrl_deriv_gain = (ctrl_deriv_gain << 15);
                  ctrl_deriv_gain = ctrl_deriv_gain/(V_sample + ctrl_deriv_offset);
     
                 /* calibration of channel4:  offset = ctrl_deriv_offset   gain = ctrl_deriv_gain */
     
                  /* switching channel 4 and 0 to A5 */
                  init_analog_front_end_calibration(SD16_DC_VOLTAGE, SD16INCH_5);
                  calibration_mode = 3;
                  num_chan_ to_calibrate = 1;
                }
              }
              else
              {
                if(calibration_mode == 3)
                {
                  /*channel 4 and 0 have been swithed on A5 and should have the same value */
                   memo_sample[nb_value_memo] = SD16MEM_CTRL_DERIV;
                  if (num_chan_ to_calibrate == 2)
                    memo_sample[nb_value_memo] = SD16MEM_DC_CURRENT;
                  else
                  {
                    if(num_chan_ to_calibrate== 3)
                      memo_sample[nb_value_memo] = SD16MEM_AC_VOLTAGE;
                    else
                    {
                      if(num_chan_ to_calibrate == 4)
                       memo_sample[nb_value_memo] = SD16MEM_AC_CURRENT;
                      else
                       memo_sample[nb_value_memo] = SD16MEM_DC_VOLTAGE;
                    }
                  }
                  nb_value_memo++;
                  if(nb_value_memo >= NB_PT_CALIB)
                  {
                    nb_value_memo = 0;
                    V_sample = average(memo_sample);
                    temp1 = (V_sample + ctrl_deriv_offset) * ctrl_deriv_gain;
                    vref_calib_interne = temp1 >> 15; /* value of A5 (AVcc-AVss)/11 */
                    if (num_chan_ to_calibrate == 1)
                    {
                          /* gain calculation of channel 0 */
                          V_sample = average(memo_sample);
                          dc_voltage_gain = vref_calib_interne;
                          dc_voltage_gain = (dc_voltage_gain << 15);
                          dc_voltage_gain = dc_voltage_gain/(V_sample + dc_voltage_offset);
     
                         /* calibration of channel0:  offset = dc_voltage_offset      gain = dc_voltage_gain  */

                         /* switching channel 0 and 2 to A5 */
                          init_analog_front_end_calibration(SD16_DC_CURRENT, SD16INCH_5);
                          num_chan_ to_calibrate= 2;
                    }
                    else
                    {
                      if(num_chan_ to_calibrate== 2)
                      {
    }
     
                                ...........      /* the same calculation is made to have the gain of the others channels */
    .
      
                     
                      }
                    }
                  }
                }
              }
            }
            SD16CCTL_DC_CURRENT &= ~SD16IFG;
            SD16CCTL_DC_VOLTAGE &= ~SD16IFG;
            SD16CCTL_AC_CURRENT &= ~SD16IFG;
            SD16CCTL_AC_VOLTAGE &= ~SD16IFG;
            SD16CCTL_CTRL_DERIV &= ~SD16IFG;

**Attention** This is a public forum