Wrong ADC Values while debugging


Question: While debugging a project, whenever a break point is hit, the ADC produces wrong results on the next conversion.  Why does this happen?  What is the work around?

Response: Let us take a look at how an ADC is created in a PSoC.  Except for the SAR6 ADC, which uses a single Analog block, all other PSoC ADCs (ADCINC, ADCINCVR, DelSig, DELSIG8/11 etc) are a combination of Analog and Digital blocks.  The block diagram of an ADCINC12 is shown below.

An SC Bloc configured as an analog modulator converts the input analog signal into a digital bit stream, whose On Time / Off Time ratio is proportional to the input signal.

0V - 50% on, 50% off
+Vref/2 - 75% on, 25% off
-Vref/2 - 25% on, 75% off
…and so on.

A counter integrates this bit stream for a fixed integration window set by a timer, and at the end of the integration cycle, the CPU reads the value in the Counter which is the ADC result.  The hardware implementation of the digital integrator is different in different ADCs, but the concept is the same.  For the ADC result to be correct, the CPU has to read the value from the counter exactly at the end of the integration cycle.  If it fails to do so, the counter will continue counting the bit stream and will result in an incorrect ADC result.

When a break point is hit while debugging, the CPU halts.  But the analog and digital blocks continue to run in the background and the counter would be counting many ADC integration cycles.  So, naturally when CPU resumes execution after the breakpoint, the value read from the counter would be wrong.  If you are debugging some other section of the program that does not have any dependency on the ADC result, then just ignore this.  When you program the device and the program runs continuously, the ADC result would be correct.  If you are debugging a section that depends on the accuracy of the ADC result, then here are some things that you can do.

1.    As the program is running, dynamically set a breakpoint after the instruction that reads the ADC result, by left clicking on the left margin of the code window (left side of the Line number).  When the program halts, the value read from the ADC would be correct.  Now clear the breakpoint, run the program and dynamically place the breakpoint again.

2.    Use the following code.

      for(i=0; i<2; i++)
         while(ADC_fIsDataAvailable() == 0);
         ADCResult = ADC_iGetData();
      asm("nop");  ---> Place breakpoint here

In the above code, the “for” loop runs two cycles.  The ADC result read during the first iteration of the for loop is corrupt. The second ADC result is clean.  So, when the break point is hit, the ADC result will always be correct.  Remember, when using a Delta sigma ADC, the for loop should be written for 3 cycles, so that the first 2 results are dropped.  For other incremental ADCs, dropping one result is enough.

3.    Instead of running the ADC in continuous sampling mode, run it in single sample mode.

      while(ADC_fIsDataAvailable() == 0);
      ADCResult = ADC_iGetDataClearFlag();
      asm("nop");  --------------------------> Break point here

When the ADC is run in single sample mode, the ADC conversion starts when the "ADC_GetSamples" function is called.  On end of conversion, the counter and timer are stopped.  They will be started only when the ADC_GetSamples function is called.  Thus, the ADC result would never be corrupt.  This applies only to incremental ADCs and can not be used for Delta sigma ADCs.