LPC84X ADC Discontinuity

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC84X ADC Discontinuity

3,382 Views
ebucha
Contributor II

Has anyone else noticed a large discontinuity while using the LPC845 ADC near mid-value?  I am seeing a range of missing codes immediately below 2048 ticks. 

I can replicate this on my own boards along with the LPCXpresso845MAX dev board using minimally modified example code.  By changing the adc_basic example to use ADC2 and connecting a bench supply with 2K/22K resistor divider to Analog header A0, I can replicate the issue by dialing the supply voltage.  Here are the missing code ranges I observe on my three LPCXpresso845MAX boards:

   2034-2047

   2037-2047

   2041-2047

The problem exists independent of sample rate and is present at much lower input impedances as well.  This is rather annoying for my application since I have bidirectional current sensors which idle at half ADC value.

Labels (2)
Tags (1)
17 Replies

2,504 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Evan,

With the design engineers involved, the problem is solved. when you do calibration for the ADC, you should set the ADC clock as a slower ADC clock frequency for example 0.5MHz. After the calibration, you can recover the ADC clock frequency to 30MHz at most.

I attach the code which you gave and modified by us, pls have a try.

BR

XiangJun Rong

bool ADC_DoSelfCalibration(ADC_Type *base, uint32_t frequency)
{
    uint32_t tmp32;
    #if 0
    /* Store the current contents of the ADC CTRL register. */
    tmp32 = base->CTRL;

    /* Start ADC self-calibration. */
    base->CTRL |= ADC_CTRL_CALMODE_MASK;

    /* Divide the system clock to yield an ADC clock of about 500 kHz. */
    base->CTRL &= ~ADC_CTRL_CLKDIV_MASK;
    base->CTRL |= ADC_CTRL_CLKDIV((frequency / 500000U) - 1U);

    /* Clear the LPWR bit. */
    base->CTRL &= ~ADC_CTRL_LPWRMODE_MASK;
    /* Delay for 200 uSec @ 500KHz ADC clock */
    SDK_DelayAtLeastUs(200U);

    /* Check the completion of calibration. */
    if (ADC_CTRL_CALMODE_MASK == (base->CTRL & ADC_CTRL_CALMODE_MASK))
    {
    /* Restore the contents of the ADC CTRL register. */
    base->CTRL = tmp32;
    return false; /* Calibration timeout. */
    }
    /* Restore the contents of the ADC CTRL register. */
    base->CTRL = tmp32;
    #else
    /* Store the current contents of the ADC CTRL register. */
    SYSCON->SYSAHBCLKCTRL0|=1<<24;
    tmp32 = base->CTRL;

    /* Divide the system clock to yield an ADC clock of about 500 kHz. */
    base->CTRL &= ~ADC_CTRL_CLKDIV_MASK;
    base->CTRL |= ADC_CTRL_CLKDIV((frequency / 500000U) - 1U);

    /* Clear the LPWR bit. */
    base->CTRL &= ~ADC_CTRL_LPWRMODE_MASK;

    /* Start ADC self-calibration. */
    base->CTRL |= ADC_CTRL_CALMODE_MASK;

    /* Check the completion of calibration. */
    while (base->CTRL & ADC_CTRL_CALMODE_MASK);
    /* Restore the contents of the ADC CTRL register. */
    base->CTRL = tmp32;
    #endif
    return true;
}

2,504 Views
1234567890
Contributor IV

bool ADC_DoSelfCalibration(ADC_Type *base, uint32_t frequency)
{
    uint32_t tmp32;
    #if 0
    /* Store the current contents of the ADC CTRL register. */
    tmp32 = base->CTRL;

 

    /* Start ADC self-calibration. */            // <== Shouldn't this be done after the step below (changing clock to 500 kHz)???
    base->CTRL |= ADC_CTRL_CALMODE_MASK;

 

    /* Divide the system clock to yield an ADC clock of about 500 kHz. */
    base->CTRL &= ~ADC_CTRL_CLKDIV_MASK;
    base->CTRL |= ADC_CTRL_CLKDIV((frequency / 500000U) - 1U);

...

0 Kudos

2,504 Views
ebucha
Contributor II

The code you are referencing is defined out (#if 0) and is from the broken FSL driver.  The updated code from their FAE (after the #else) does move the calibration enable after the change of the CLKDIV. 

However, changing the placement of the calibration start alone doesn't fix the problem unless the ADC clock has been previously enabled in SYSCON->SYSAHBCLKCTRL0.  Further, I prefer setting CTRL in a single write as recommended in the user manual section 27.3.4 step 2.

0 Kudos

2,504 Views
ebucha
Contributor II

XiangJun,

   This does appear to resolve the problem. The FSL driver provided in the example code (2.3.1) is already trying to do this but there appear to be two problems which the new code resolves:

  1. ADC_DoSelfCalibration assumes that the ADC bit is enabled in SYSCON->SYSAHBCLKCTRL0. This isn't the case with the way the example code and driver set up the ADC.
  2. ADC_DoSelfCalibration starts the calibration BEFORE reducing the ADC clock to 500kHz.

This means that ADC_DoSelfCalibration shows the outward appearance of calibration succeeding when it's not actually running at all or is clocked too fast. I also noted that, as of SDK 3.5.0, this problem still exists in the FSL driver. I have updated my fls_adc driver to 3.5.0 and applied the following changes:

bool ADC_DoSelfCalibration(ADC_Type *base, uint32_t frequency) {
   uint32_t tmp32;
   uint32_t ctrl_value;

   /* Store the current contents of the ADC CTRL register. */
   tmp32 = base->CTRL;

   /* Ensure the ADC clock is enabled in SYSCON. */

   SYSCON->SYSAHBCLKCTRL0 |= SYSCON_SYSAHBCLKCTRL0_ADC_MASK;

   

   ctrl_value = base->CTRL;

   /* Divide the system clock to yield an ADC clock of about 500 kHz. */
   ctrl_value &= ~ADC_CTRL_CLKDIV_MASK;
   ctrl_value |= ADC_CTRL_CLKDIV((frequency / 500000U) - 1U);
   /* Clear the LPWR bit. */
   ctrl_value &= ~ADC_CTRL_LPWRMODE_MASK;
   /* Start ADC self-calibration. */
   ctrl_value |= ADC_CTRL_CALMODE_MASK;

   /* Set the new CTRL value in a single write as recommended by the datasheet. */
   base->CTRL = ctrl_value;

   /* Delay for 200 uSec @ 500KHz ADC clock */
   SDK_DelayAtLeastUs(200U);

   /* Check the completion of calibration. */
   if (ADC_CTRL_CALMODE_MASK == (base->CTRL & ADC_CTRL_CALMODE_MASK)) {
      /* Restore the contents of the ADC CTRL register. */
      base->CTRL = tmp32;
      return false; /* Calibration timeout. */
   }
   /* Restore the contents of the ADC CTRL register. */
   base->CTRL = tmp32;

   return true;

}

I hope that it will be patched ASAP to avoid further confusion. Thank you for the assistance in getting this figured out.

Evan Buchanan

0 Kudos

2,504 Views
ebucha
Contributor II

I'm having less than stellar results with NXP support in getting this resolved or even confirmed. 

I'm including a link to sample code for the LPCXpresso845MAX should someone here want to verify the behavior.  You can do this by programming the firmware to your board and then attaching to the running device via LinkServer in MCUXpresso.  You can see the configuration by restarting and then resuming. Pins J6-6 and J1-6 must be jumpered to carry signal from DAC0 to ADC0.

The firmware generates random noise (default) or a sine wave at ~1.65V on DAC0.  It simultaneously samples ADC0 to generate a histogram of all ADC codes present.  It periodically checks for the presence of codes between 1998 and 2097 outputting the number of missing codes. If the count is less than 20, a list will be printed as shown here:

pastedImage_1.png

I'm interested in seeing if the problem is reproducible on newer chip revisions.  I will be checking on a newer LPC845-BRK shortly.

The code is available on my Google Driver here: https://drive.google.com/open?id=1eOXafzRHB2a7cj2CsgvzIe1x20INcBPq 

0 Kudos

2,504 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Evan

I have downloaded your code, I will test the code later and tell you the result next week.

BR

XiangJun Rong

0 Kudos

2,504 Views
ebucha
Contributor II

Shortly after I posted my last message support was able to reproduce the problem on the dev board I sent them.  This is a positive development, but more data never hurts, especially if there is a production date component to the problem.

Thanks for the additional effort,

Evan

0 Kudos

2,504 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Evan,

I can reproduce your issue on my LPCXpresso845MAX board, I have created a ticket for AE team, I will help AE team  to duplicate the issue and hear their opinion for the root cause, then determine if we list the issue in the errata.

BR

Xiangjun Rong

0 Kudos

2,504 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Evan,

For the ADC missing code issue of LPC84x, I have notified the AE team. As you know there is not any workaround or whatever to avoid this issue. Sorry for not helping you

BR

Xiangjun Rong

0 Kudos

2,504 Views
rainald_koch
Contributor II

Hi all,

this case of missinge codes is less annoying than the one I encountered with an acceleration sensor. There were large intervals of acceleration values mapped onto the same codes, adjacent to gaps of missing codes. In this case, however, there is no large interval of voltages mapped to the same code. This allows a workaround that is ~100% effective (decrease in resolution from 12 bit to 11.995 bit) and "easy" in the sense of now extra components on the board and only a few lines of extra code: Calibrate away the gap by using different offset values for the code ranges above and below the gap.

If you planned to do a calibration anyway, the extra cost is minimal.

If not, check whether 11 bit resolution is sufficient and if so, map the input range to half the code range.

If not, chose another chip.

Rainald

0 Kudos

2,504 Views
blarg
Contributor I

Rainald Koch wrote:

In this case, however, there is no large interval of voltages mapped to the same code. This allows a workaround that is ~100% effective (decrease in resolution from 12 bit to 11.995 bit) and "easy" in the sense of now extra components on the board and only a few lines of extra code: Calibrate away the gap by using different offset values for the code ranges above and below the gap.

This does not seem like a viable approach given the gap varies with each part.  If one were to try and calibrate this out in production, it would take too much test time to be precise.

And what if the code gap varies with temperature, voltage, or other variables?

If not, check whether 11 bit resolution is sufficient and if so, map the input range to half the code range.

It isn't "11 bits".  The code gap is as much as 15 codes, which is 4 bits.

Engineers don't choose a microcontroller with a 12 bit ADC and then are happy with it acting like an unpredictable 8 bit ADC.

If not, chose another chip.

If the NXP response is that the LPC845 ADC code gap is acceptable, then, yes, I'd steer away from NXP microcontrollers.  Having a gap like that right in mid range is clearly unacceptable and doesn't meet datasheet spec for INL and DNL.

JB

2,504 Views
rainald_koch
Contributor II

:-o  Using half the range of a 12-bit ADC yields 11-bit resolution, not 8 bit.

0 Kudos

2,504 Views
ebucha
Contributor II

Xiangjun,

We have also contacted support through our sales rep referencing this post.  I would be more than happy for this to be a software or configuration issue but your reply implies that is not the case.  If this is a known hardware issue, the lack of an Errata is unacceptable.  Thank you for running this up the chain on your end.

2,504 Views
blarg
Contributor I

xiangjun.rong wrote:

Hi, Evan,

For the ADC missing code issue of LPC84x, I have notified the AE team. As you know there is not any workaround or whatever to avoid this issue. Sorry for not helping you

BR

Xiangjun Rong

Xiangjun,

Your reply, given you know there is no workaround, suggests this is a known issue, that Evan wasn't the first to encounter it.  Yet there is no entry in the errata list for the LPC84x.  Will the Errata be updated?  When was this issue first discovered?

Also, does this issue afflict other LPC8xx chips?  For example, I have a design with an LPC804 which also has a 12 bit ADC which seems similar to the LPC84x series.  I haven't tested the ADC, but I am worried it also has this defect.  I was considering moving the project to an LPC84x series, but this ADC issue has taken the motivation out of that.  There's a lot of choice in the low cost Cortex-M microcontroller market, so this ADC issue needs to get fixed.

JB

2,504 Views
ebucha
Contributor II

Xiangjun,

I've done a bit more testing to better quantify the problem. 

First, I ran a quick test with a 500Hz ~50mV sine wave from a 50 ohm signal generator on my worst LPCXpresso845MAX board.  The sample plot makes it easy to visualize the gap in codes:

500Hz sine ADC.png

Second, I collected date codes and more precise code gap sizes for the LPC845 chips I am looking at:

LPCXpresso845MAX Boards:

Date CodeMissing Code Count
17-2713
17-279
17-447

My Custom Board:

Date CodeMissing Code Count
17-4415

I'm seeing the problem in both batches of chips I have on hand.

Lastly, I ran a test over night with a source at 1.65V.  This results in readings toggling back and forth across the discontinuity due to noise.  Over many hours and millions of samples, not once did I see a missing code re-appear.

So to summarize:

  • Missing codes aren't dependent on source impedance (50ohm - 200kohm) or sample rate (4ksps - 1.2Msps)
  • ADC Calibration (or removal thereof)  doesn't impact the missing codes
  • The size of the code gap is consistent on a given chip at room temperature but varies chip-to-chip
  • The gap is much larger than the INL typical spec leads us to expect worst case
  • The missing codes never appear even with noise present in the signal
  • Values below the gap are still nicely linear - Actual voltage can be derived if the size of the code gap is known

Other engineers on my end are interested to see if the problem can be replicated.  We suspect an unexpected error term in the lower half of the successive approximation DAC or similar issue.

Thanks,

Evan Buchanan

2,504 Views
ebucha
Contributor II

Xiangjun,

Using a 50 ohm waveform generator as a source, I still see roughly the same number of missing codes (+/-1).  The problem doesn't appear to be source impedance dependent.

Thanks for the assistance,

Evan

0 Kudos

2,504 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Evan,

if you use a low impedance voltage source to have a test, for example connect the waveform generator output(have it output DC voltage) to ADC analog channel, then have the output DC voltage to about 1.6V, does the missing code appear?

Xiangjun Rong