Capacity Measurement MPR121

12 Oct 2012

Dear all,

In contrary to many other MPR121 projects where I found information on, I want to use the Freescale MPR121 (placed on a Sparkfun breakout board) to perform a capacity measurement instead of only touch sensing.

The problem is that when I read out the capacity measurment, this doesn't correspond to what's expected based on the equations. Let me try to explain as accurately as possible what I have done:

  • According to Freescale's documentation the relation between the measured capacity and the given output ADC is as follows:

C = (I * T * 1024) / (Vdd * ADC)

where C: capacity to be measured I: current, Charge Discharge Current (CDC), set in the Analog Front End (AFE) Configuration Register. T: Charge Discharge Time (CDT), set in the Filter Configuration Register. Vdd: the breakout board is provided a 3.3V supply ADC: this is a counter value that represents the voltage inversely proportional to the measured Capacitance (C).

  • To verify measurements, I have connected a known capacity to the breakout board sensor 0.
  • I want to read the ADC value from the register, as this represents the measured capacity. This is a 10bit number which I read as follows:

void read_capacity( void )
{

    short int  ADC = 0;
   
    ADC =     mpr121.read(EFD0HB);  // Read first byte (MSByte)
    ADC <<= 8;                      // Shift byte to MSByte position
    ADC |=    mpr121.read(EFD0LB);  // Past second byte (LSByte) into value     

    
    pc.printf("ADC = %i\n",  ADC);
    
     
    pc.printf("\n\n");
    
}

where EFD0HB and EFD0LB are respectively the high byte and low byte registry addresses for the ADC value of sensor channel 0.

  • To make this capacity measurement work, I can configure some settings. Among other filter settings, I can set 'I' (Charge Discharge Current CDC) and 'T' (Charge Discharge Time CDT) to ensure that the measured capacity is within allowed range. This allowed range is calculated as:

C_low = (I*T)/(Vdd-0.7) and C_high=(I*T)/0.7.

The used code to set the CDC and CDT (and some other filter values that make it a more robust measurement via averaging etcetera) is:

void set_capacity_measurement( void )
{ //For more information see Texas Instruments Application Note AN3889
 
    int FFI;                // [samples] First Filter Iterations (FFI)
    int CDC;                // [uA]      Charge Discharge Current (CDC)
    unsigned char AFE_CFG_value = 0;
    
    int SFI;                // [samples] Second Filter Iterations (FFI)
    int ESI;                // [ms]      Electrode Sample Interval
    int CDT;                // [us]      Charge Discharge Time (CDT)          
    unsigned char FIL_CFG_value = 0;
 
 
 // Set the electrode config to transition to stop mode
 mpr121.write(ELE_CFG,0x00); // write value to register
 
 //Analog Front End (AFE) CONFIGURATION REGISTER
 FFI  = 3;  // value: 0:samples taken 6 (default)| 1:samples taken 10 | 2:samples taken 18 | 3:samples taken 34
 CDC  = 4; // [uA] range [0 - 63]
 
 FFI <<= 6;                                // shift to first two bits of register value
 AFE_CFG_value = (FFI|CDC);                // combine inputs to correct register value
  
 mpr121.write(AFE_CFG,AFE_CFG_value); // write value to register 

 //Filter CONFIGURATION REGISTER
 CDT = 7; // range [1 - 7] = [0.5us - 32us]  note: value 0 is invalid
 SFI = 0; // range [0 - 3] = [4,6,10,18] samples
 ESI = 7; // range [0 - 7] = [1,2, 128ms]    

 CDT <<= 5;                                  // shift to bits 7:5 of register value
 SFI <<= 3;                                  // shift to bits 4:3 of register value 
 FIL_CFG_value = ((CDT|SFI)|ESI);           // combine inputs to correct register value

 mpr121.write(FIL_CFG,FIL_CFG_value); // write value to register

 // Set the electrode config to transition to active mode
 mpr121.write(ELE_CFG,0x0C); // write value to register


 pc.printf("Capacity Settings Set\n");
 
}
  • So now I have connected a known Capacity, set 'I' and 'T' to ensure this Capacity value to be within the possible measurement range, calculated with the first equation what ADC value to expect, and read the ADC value.

Unfortunately, the obtained ADC value doesn't correspond to the calculated (expected) ADC value (not even close). I haven't been able to find any relation (multiplication or offset) between the ADC values expected and the ADC values read from the register.

I hope somebody has an idea where to look for the cause of this problem? Or a suggestion what to try?

For completeness I have added two documents regarding the MPR121 and capacity measurement.

Many thanks in advance!

Relevant MPR121 documentation: /media/uploads/raalst1/an3889_capacitance_sensing_settings.pdf and /media/uploads/raalst1/mpr121_data_sheet.pdf

12 Oct 2012

Before you delve too far into your code what type of cap were you measuring? Some caps have really poor tolerances (-20% +80% on Y5V ceramic caps for example) so your code could be working fine

12 Oct 2012

Dear Martin,

Thank you for your fast response. Regarding the capacitors; we have used ceramic capacitors from different values, e.g. 10p, 12p, 22p, 33p, 56p, 68p and n10. All with a single black color band on top. With some help of Google, if I am not mistaken this means a tolerance of +-20% for these capacitors.

Furthermore, I am aware that additional wiring will also have some influence here, but this should also be fine in our setup.

The difference between the expected measurement outcome and the read measured output ranges from approximately 35% up to 55% for four different measurements.

So I don't expect tolerances to be the cause here.

13 Oct 2012

@ R A Have you checked with another LRC meter ? You have to isolate the cause of the problem . You can't be sure if the "strange" readings comes from unexpected capacitor value or meter error . Can you calibrate your meter readings with a known calibrated one ? Does your meter give the same reading , each time you meter the capacitor ? Check with different capacitors a b c and if you get A B C readings all the time , the meter is working correctly but may need calibration or has a formula error ...

Regards , Christos

16 Oct 2012

@XM; Currently, I haven't got the possibility to verify the capacitance of the components by measuring with another measurement device.

@All,

I have done additional measurements to gain more insight. Let me share the results:

  • I have performed different measurements with the same settings only now by using different components representing the same capacitance value. The result is the same measured output ADC, so the measurement is consistent and the deviation between expected measurement outcome and measured outcome isn't due to inaccuracy of the capacitance components itself.
  • I measured each component with a specific capacitance value for multiple settings of Charge Discharge Time (CDT) and Charge Discharge Current (CDC). I noticed that the CDT set influences the factor (which I call Alpha) between (according to the equations) expected ADC value (ADC_exp) and measured ADC value (ADC_meas). Here Alpha = ADC_meas / ADC_exp. So for different values of CDC but the same CDT a linear trend is visualized as seen in the next figure for the case that CDT=0.5 [us]. The multiplication factor Alpha is constant for a certain CDT, but changes with other CDT values.

/media/uploads/raalst1/cdtconstantlineartrend.jpg

  • I also looked at the relations between Alpha, CDT set and the known Capacitance Component value used to verify the measurement. The following figures are the result:

/media/uploads/raalst1/alpha_capacitance.jpg

and

/media/uploads/raalst1/alpha_cdt.jpg

  • Note that their appears to be a linear relation between Alpha and CDT (second figure).

So the conclusion is that the multiplication Alpha between ADC_expected and ADC_measured is dependend on the set CDT as well as on the to be measured capacitance C. So the equation representing the relation between capacity and ADC as given by Freescale (see first post and note that in these formulas I = CDC and T = CDT):

C = (I * T * 1024) / (Vdd * ADC) or transformed to ADC = (I * T * 1024)/ (Vdd* C)

seems to me to be more like

ADC = (I * T * 1024)/ (Vdd* C) * Alpha(C,CDT)

where Alpha(C,CDT) represent a function depdend on the capacity to be measured C and CDT, the Charge Discharge Time set.

As I want to measure different at forehand unknown capacities by obtaining a measured output ADC, I am wondering how to cope with this? Does anybody has ideas how to be able to use this MPR121 sensor to measure the capacity keeping in mind the results I previously introduced? Or directions on how to find the cause of this Alpha(C,CDT) as a step towards the solution?

Many thanks!