EmbeddedRelated.com
Forums

ADC Issue

Started by Jerry January 29, 2012
>> So the question remains: why such poor performance with the LPC1768's built-in ADC?
>> In its current state, it's nearly unusable without extensive filtering and averaging to reject the bogus conversions it's constantly spewing out.

The answer is: either your code is bad or the hardware/pcb is bad. The problem is NOT the LPC17XX.

I have a LPC1766 project right now. My own board design. I run the ADC on 5CHs mux'd continuous.
I also have debug traps on the DONE and OVERRUN bits to check them every conversion.
I use an ISR to service the ADC, and also have RTOS task processing the ADC data.
About 50 conversions every second, and this is running 24/7.
I never see any errors at all - ZERO.

It it very easy to get the ADC code wrong, and that will cause all kinds of crazy problems.
It is very picky. My guess is you have something wrong with your code.

Chris.


An Engineer's Guide to the LPC2100 Series

--- In l..., "Chris" wrote:
> The answer is: either your code is bad or the hardware/pcb is bad. The problem is NOT the LPC17XX.
>
> I have a LPC1766 project right now. My own board design. I run the ADC on 5CHs mux'd continuous.
> I also have debug traps on the DONE and OVERRUN bits to check them every conversion.
> I use an ISR to service the ADC, and also have RTOS task processing the ADC data.
> About 50 conversions every second, and this is running 24/7.
> I never see any errors at all - ZERO.
>
> It it very easy to get the ADC code wrong, and that will cause all kinds of crazy problems.
> It is very picky. My guess is you have something wrong with your code.

Well, it's good to hear that the ADC at the chip level works. At this point, I haven't completed my own board design, so I'm using a development board. The schematics of this board look like they are treating the analog references and grounds properly (with bypass caps, ferrite beads, etc.), but I don't know if the PCB is laid out properly to deal with all the typical noise issues involved.

Code error is certainly a possibility, but the LPC1768 has such a simple ADC interface that I don't think this is too high a likelyhood.

The strange thing I see is the overrun bit is always set when a bad conversion occurs. The user's manual says this bit is only used in burst mode, which I don't use. I'm also 100% certain that my code does not try to initiate another conversion before the previous one finishes. Likewise, I'm 100% certain that a conversion is complete before I return data to the caller. This is pretty easy to get right as the done bit and the result bits are in the same register and the done bit is cleared when the register is read -- if the done bit is set, then the data bits are valid. I don't see any ambiguity here. I'm only using one channel, so there's no chance I'm mistaking done on one channel with done on another.

The user's manual says to be careful about mixing the use of the global data register with usage of the individual channel's data registers since the done and overrun bits can get out of sync if this is done. I've tried both ways -- but only way one at a time -- and didn't see any difference in the error rate.

I'm still very motivated to get the internal ADC working reliably, so any coding suggestions you can offer would be appreciated.

Il 13/02/2012 06:05, Jerry ha scritto:
>
>
> --- In l... ,
> "Chris" wrote:
> > The answer is: either your code is bad or the hardware/pcb is bad.
> The problem is NOT the LPC17XX.
> >
> > I have a LPC1766 project right now. My own board design. I run the
> ADC on 5CHs mux'd continuous.
> > I also have debug traps on the DONE and OVERRUN bits to check them
> every conversion.
> > I use an ISR to service the ADC, and also have RTOS task processing
> the ADC data.
> > About 50 conversions every second, and this is running 24/7.
> > I never see any errors at all - ZERO.
> >
> > It it very easy to get the ADC code wrong, and that will cause all
> kinds of crazy problems.
> > It is very picky. My guess is you have something wrong with your code.
>
> Well, it's good to hear that the ADC at the chip level works. At this
> point, I haven't completed my own board design, so I'm using a
> development board. The schematics of this board look like they are
> treating the analog references and grounds properly (with bypass caps,
> ferrite beads, etc.), but I don't know if the PCB is laid out properly
> to deal with all the typical noise issues involved.
>
> Code error is certainly a possibility, but the LPC1768 has such a
> simple ADC interface that I don't think this is too high a likelyhood.
>
> The strange thing I see is the overrun bit is always set when a bad
> conversion occurs. The user's manual says this bit is only used in
> burst mode, which I don't use. I'm also 100% certain that my code does
> not try to initiate another conversion before the previous one
> finishes. Likewise, I'm 100% certain that a conversion is complete
> before I return data to the caller. This is pretty easy to get right
> as the done bit and the result bits are in the same register and the
> done bit is cleared when the register is read -- if the done bit is
> set, then the data bits are valid. I don't see any ambiguity here. I'm
> only using one channel, so there's no chance I'm mistaking done on one
> channel with done on another.
>
> The user's manual says to be careful about mixing the use of the
> global data register with usage of the individual channel's data
> registers since the done and overrun bits can get out of sync if this
> is done. I've tried both ways -- but only way one at a time -- and
> didn't see any difference in the error rate.
>
> I'm still very motivated to get the internal ADC working reliably, so
> any coding suggestions you can offer would be appreciated.
>
Post me your code privately if you prefer and I will check it.
I am an NXP partner, and I am using LPC17xx adc very frequently. Until
now I saw that the major problems related to the internal adc are errors
on firmware. I can say that LPC17xx adcs are one of the best you may
find in a ARM/Cortex core; I saw adc of others silicon makers that
aren't so good at 12MHz frequency.
>



--- In l..., "M. Manca" wrote:
> Post me your code privately if you prefer and I will check it.
> I am an NXP partner, and I am using LPC17xx adc very frequently. Until
> now I saw that the major problems related to the internal adc are errors
> on firmware. I can say that LPC17xx adcs are one of the best you may
> find in a ARM/Cortex core; I saw adc of others silicon makers that
> aren't so good at 12MHz frequency.

Thanks for the offer! Since my code is neither proprietary or long, I'll post it here. One thing to keep in mind about the following code is that it currently is only set up for ADC channel 0 -- I haven't added code to work with the other channels yet. When I tried other channels, I just modified the code in the init routine to suit. Thanks for any insight you, or other forum members may be able to provide.
#include "include/LPC1768.h"
#include "include/types.h"
#include "include/macros.h"
#include "include/proc.h"
#include "include/globals.h"
#include "include/jrtos.h"
static U32 channelData[8]; // Data read from ADC channels
void
ADCInit(void)

{

PCONP |= PCONP_PCAD; // Enable ADC in the Power Control for Peripherals register
AD0CR |= AD0CR_PDN; // Enable the ADC in the ADC control register
AD0CR = (AD0CR & 0xffff00ff) | (3 << AD0CR_CLKDIV_BIT); // Set ADC clock divisor
PINSEL1 = (PINSEL1 & ~PINSEL1_P0_23_MASK) | (0x01 << PINSEL1_P0_23_BIT); // Select the ADC function on P0.23 (ADC0)
PINMODE1 = (PINMODE1 & 0xffff3fff) | (0x02 << PINMODE_OD1_P1_14OD_BIT); // Set pin mode to neither pull-up or pull-down

Irq_20_to_23_Priority |= ADC_PRIO << Irq_20_to_23_Priority_PRI_22_BIT; // set interrupt priority
Irq_0_to_31_Set_Enable |= 1 << 22; // enable interrupts on vector 22 (ADC)

AD0INTEN = AD0INTEN_ADGINTEN; // Only global DONE flag in Data register will generate an interrupt

}
//
// ADCRead
//
// Interrupt-driven read of ADC channel. Starts a conversion on a channel and sleeps until the conversion is complete.
//
S32
ADCRead(U8 channel)

{

U32 sample;

if((channel > 7) || (channel < 0))
return(-1); // Channel must be in range 0-7

channelData[channel] = 0;

AD0CR &= AD0CR_CLKDIV_MASK | AD0CR_PDN_MASK; // Clear all but clkdiv and PDN bits in control register
AD0CR = (AD0CR & 0xffffff00) | (1 << channel); // Set channel number to sample
AD0CR = (AD0CR & 0xf8ffffff) | (1 << AD0CR_START_BIT); // Start conversion on selected channel

OsSleep((U32)&channelData[channel], curtcb->priority); // wait for conversion complete

if(!(channelData[channel] & AD0GDR_DONE))
printf("ADCRead: interrupt without DONE bit set\r");

sample = (channelData[channel] & AD0GDR_RESULT_MASK) >> AD0GDR_RESULT_BIT;
return(sample); // Isolate 12 result bits and return

}
//
// ADCReadPoll
//
// Polling version of ADCRead. Starts a conversion on a channel and waits for completion by polling the DONE bit in the
// global data register.
//
S32
ADCReadPoll(U8 channel)

{

U32 sample;

if((channel > 7) || (channel < 0))
return(-1); // Channel must be in range 0-7

AD0CR &= AD0CR_CLKDIV_MASK | AD0CR_PDN_MASK; // Clear all but clkdiv and PDN bits in control register
AD0CR = (AD0CR & 0xffffff00) | (1 << channel); // Set channel number to sample
AD0CR = (AD0CR & 0xf8ffffff) | (1 << AD0CR_START_BIT); // Start conversion on selected channel

while(!((sample = AD0GDR) & AD0GDR_DONE))
; // Wait for conversion complete

sample = (sample & AD0GDR_RESULT_MASK) >> AD0GDR_RESULT_BIT; // Isolate result bits (12)
return(sample);
}
void
ADC_IRQHandler(void)

{

U32 sample;
U8 channel;

sample = AD0GDR;
channel = (sample & AD0GDR_CHN_MASK) >> AD0GDR_CHN_BIT;
channelData[channel] = sample;

OsWakeup((U32)&channelData[channel]);

}

Il 13/02/2012 17:16, Jerry ha scritto:
I modified init and adc read in poll mode. If you would use irq reading
you have to modify the corresponding function in a similar way
I did with polling function.

#include "include/LPC1768.h"
#include "include/types.h"
#include "include/macros.h"
#include "include/proc.h"
#include "include/globals.h"
#include "include/jrtos.h"

static U32 channelData[8]; // Data read from ADC channels

#define CLKDIV 8 // I suppose 100MHz internal clock -> 100/8 12.5MHz < 13MHz
void ADCInit(void)
{

PCONP |= PCONP_PCAD; // Enable ADC in the Power Control for Peripherals
register
/*
AD0CR = (AD0CR & 0xffff00ff) | (3 << AD0CR_CLKDIV_BIT); // Set ADC clock
divisor
AD0CR |= AD0CR_PDN; // Enable the ADC in the ADC control register
*/
AD0CR = AD0CR_PDN | (CLKDIV << 8); // Enable the ADC in the ADC control
register
PINSEL1 = (PINSEL1 & ~PINSEL1_P0_23_MASK) | (0x01 << PINSEL1_P0_23_BIT);
// Select the ADC function on P0.23 (ADC0)
PINMODE1 = (PINMODE1 & 0xffff3fff) | (0x02 << PINMODE_OD1_P1_14OD_BIT);
// Set pin mode to neither pull-up or pull-down

Irq_20_to_23_Priority |= ADC_PRIO << Irq_20_to_23_Priority_PRI_22_BIT;
// set interrupt priority
Irq_0_to_31_Set_Enable |= 1 << 22; // enable interrupts on vector 22 (ADC)
/* start testing polling mode
AD0INTEN = AD0INTEN_ADGINTEN; // Only global DONE flag in Data register
will generate an interrupt
*/
}

//
// ADCRead
//
// Interrupt-driven read of ADC channel. Starts a conversion on a
channel and sleeps until the conversion is complete.
//
S32
ADCRead(U8 channel)

{

U32 sample;

if((channel > 7) || (channel < 0))
return(-1); // Channel must be in range 0-7

channelData[channel] = 0;

AD0CR &= AD0CR_CLKDIV_MASK | AD0CR_PDN_MASK; // Clear all but clkdiv and
PDN bits in control register
AD0CR = (AD0CR & 0xffffff00) | (1 << channel); // Set channel number to
sample
AD0CR = (AD0CR & 0xf8ffffff) | (1 << AD0CR_START_BIT); // Start
conversion on selected channel

OsSleep((U32)&channelData[channel], curtcb->priority); // wait for
conversion complete

if(!(channelData[channel] & AD0GDR_DONE))
printf("ADCRead: interrupt without DONE bit set\r");

sample = (channelData[channel] & AD0GDR_RESULT_MASK) >> AD0GDR_RESULT_BIT;
return(sample); // Isolate 12 result bits and return

}

//
// ADCReadPoll
//
// Polling version of ADCRead. Starts a conversion on a channel and
waits for completion by polling the DONE bit in the
// global data register.
//
#define AD0CR_CLEAR_CHANNELS_MASK ~(0x07UL)
//S32
U32 ADCReadPoll(U8 channel)
{
//U32 sample;
volatile U32 sample, *pAdcData=&AD0DR0;

pAdcData = pAdcData[channel];

/*
if((channel > 7) || (channel < 0))
return(-1); // Channel must be in range 0-7
AD0CR &= AD0CR_CLKDIV_MASK | AD0CR_PDN_MASK; // Clear all but clkdiv and
PDN bits in control register
*/
/*
AD0CR = (AD0CR & 0xffffff00) | (1 << (channel & 0x07)); // Set channel
number to sample
AD0CR = (AD0CR & 0xf8ffffff) | (1 << AD0CR_START_BIT); // Start
conversion on selected channel
while(!((sample = AD0GDR) & AD0GDR_DONE))
; // Wait for conversion complete
*/
AD0CR &= AD0CR_CLEAR_CHANNELS_MASK;
do
{
AD0CR |= (1 << (channel & 0x07));
while(!(*pAdcData & (1 << 31)))
;
} while(*pAdcData & (1 << 30)); // overrun management
sample = ( (*pAdcData) >> 4) & 0x00000fff;
/*
sample = (sample & AD0GDR_RESULT_MASK) >> AD0GDR_RESULT_BIT; // Isolate
result bits (12)
*/
return(sample);
}

void
ADC_IRQHandler(void)

{

U32 sample;
U8 channel;

sample = AD0GDR;
channel = (sample & AD0GDR_CHN_MASK) >> AD0GDR_CHN_BIT;
channelData[channel] = sample;

OsWakeup((U32)&channelData[channel]);

}
> #include "include/LPC1768.h"
> #include "include/types.h"
> #include "include/macros.h"
> #include "include/proc.h"
> #include "include/globals.h"
> #include "include/jrtos.h"
>
> static U32 channelData[8]; // Data read from ADC channels
>
> void
> ADCInit(void)
>
> {
>
> PCONP |= PCONP_PCAD; // Enable ADC in the Power Control for
> Peripherals register
> AD0CR |= AD0CR_PDN; // Enable the ADC in the ADC control register
> AD0CR = (AD0CR & 0xffff00ff) | (3 << AD0CR_CLKDIV_BIT); // Set ADC
> clock divisor
> PINSEL1 = (PINSEL1 & ~PINSEL1_P0_23_MASK) | (0x01 <<
> PINSEL1_P0_23_BIT); // Select the ADC function on P0.23 (ADC0)
> PINMODE1 = (PINMODE1 & 0xffff3fff) | (0x02 <<
> PINMODE_OD1_P1_14OD_BIT); // Set pin mode to neither pull-up or pull-down
>
> Irq_20_to_23_Priority |= ADC_PRIO << Irq_20_to_23_Priority_PRI_22_BIT;
> // set interrupt priority
> Irq_0_to_31_Set_Enable |= 1 << 22; // enable interrupts on vector 22 (ADC)
>
> AD0INTEN = AD0INTEN_ADGINTEN; // Only global DONE flag in Data
> register will generate an interrupt
>
> }
>
> //
> // ADCRead
> //
> // Interrupt-driven read of ADC channel. Starts a conversion on a
> channel and sleeps until the conversion is complete.
> //
> S32
> ADCRead(U8 channel)
>
> {
>
> U32 sample;
>
> if((channel > 7) || (channel < 0))
> return(-1); // Channel must be in range 0-7
>
> channelData[channel] = 0;
>
> AD0CR &= AD0CR_CLKDIV_MASK | AD0CR_PDN_MASK; // Clear all but clkdiv
> and PDN bits in control register
> AD0CR = (AD0CR & 0xffffff00) | (1 << channel); // Set channel number
> to sample
> AD0CR = (AD0CR & 0xf8ffffff) | (1 << AD0CR_START_BIT); // Start
> conversion on selected channel
>
> OsSleep((U32)&channelData[channel], curtcb->priority); // wait for
> conversion complete
>
> if(!(channelData[channel] & AD0GDR_DONE))
> printf("ADCRead: interrupt without DONE bit set\r");
>
> sample = (channelData[channel] & AD0GDR_RESULT_MASK) >> AD0GDR_RESULT_BIT;
> return(sample); // Isolate 12 result bits and return
>
> }
>
> //
> // ADCReadPoll
> //
> // Polling version of ADCRead. Starts a conversion on a channel and
> waits for completion by polling the DONE bit in the
> // global data register.
> //
> S32
> ADCReadPoll(U8 channel)
>
> {
>
> U32 sample;
>
> if((channel > 7) || (channel < 0))
> return(-1); // Channel must be in range 0-7
>
> AD0CR &= AD0CR_CLKDIV_MASK | AD0CR_PDN_MASK; // Clear all but clkdiv
> and PDN bits in control register
> AD0CR = (AD0CR & 0xffffff00) | (1 << channel); // Set channel number
> to sample
> AD0CR = (AD0CR & 0xf8ffffff) | (1 << AD0CR_START_BIT); // Start
> conversion on selected channel
>
> while(!((sample = AD0GDR) & AD0GDR_DONE))
> ; // Wait for conversion complete
>
> sample = (sample & AD0GDR_RESULT_MASK) >> AD0GDR_RESULT_BIT; //
> Isolate result bits (12)
> return(sample);
> }
>
> void
> ADC_IRQHandler(void)
>
> {
>
> U32 sample;
> U8 channel;
>
> sample = AD0GDR;
> channel = (sample & AD0GDR_CHN_MASK) >> AD0GDR_CHN_BIT;
> channelData[channel] = sample;
>
> OsWakeup((U32)&channelData[channel]);
>
> }



Sorry about the messed up formatting. It looked good in preview, but not after the message was posted.

The original file can be downloaded here: http://gardnerwx.com/adc-lpc1768.c

--- In l..., "M. Manca" wrote:
> Il 13/02/2012 17:16, Jerry ha scritto:
> I modified init and adc read in poll mode. If you would use irq reading
> you have to modify the corresponding function in a similar way
> I did with polling function.

Thanks for the comments on my code.

I noticed two changes you made that I want to discuss:

The first is in the lines

#define CLKDIV 8 // I suppose 100MHz internal clock -> 100/8 12.5MHz < 13MHz

AD0CR = AD0CR_PDN | (CLKDIV << 8); // Enable the ADC in the ADC control
register

Looking at the LPC1768 user's manual I see that in PCLKSEL0 the PCLK_ADC bits ate set to 00 on reset, which means the ADC is clocked at CCLK/4, which in this case is (100 MHz / 4) = 25 MHz. Setting the CLKDIV bits to 8 in the ADC CR0 register would result in an ADC clock rate of (25 MHz / (8 + 1)) = 2.8 MHz. Does the ADC need to run this slow, or did you not take the default division of CCLK by 4 into account?

I see in the polling code you're continuously doing conversions until the done bit is set and the overrun bit is not set. Since I see the overrun bit set when the ADC has a misconversion, I can understand why you're doing this. However, the user's manual says that the overrun bit is only used in burst mode, which is not the case here. Is there something missing from the user's manual regarding overrun?

The user's manual says this about the overrun bit:

"This bit is 1 in burst mode if the results of one or more conversions was (were) lost and overwritten before the conversion that produced the result in the RESULT bits.This bit is cleared by reading this register."

Since the bit is cleared by reading the data register, do you ever see it set, because wouldn't it be cleared when you read the data register to check the done bit in the body of the do while loop?

Il 13/02/2012 22:55, Jerry ha scritto:
>
>
> --- In l... , "M.
> Manca" wrote:
> > Il 13/02/2012 17:16, Jerry ha scritto:
> > I modified init and adc read in poll mode. If you would use irq reading
> > you have to modify the corresponding function in a similar way
> > I did with polling function.
>
> Thanks for the comments on my code.
>
> I noticed two changes you made that I want to discuss:
>
> The first is in the lines
>
> #define CLKDIV 8 // I suppose 100MHz internal clock -> 100/8 > 12.5MHz < 13MHz
>
> AD0CR = AD0CR_PDN | (CLKDIV << 8); // Enable the ADC in the ADC control
> register
>
> Looking at the LPC1768 user's manual I see that in PCLKSEL0 the
> PCLK_ADC bits ate set to 00 on reset, which means the ADC is clocked
> at CCLK/4, which in this case is (100 MHz / 4) = 25 MHz. Setting the
> CLKDIV bits to 8 in the ADC CR0 register would result in an ADC clock
> rate of (25 MHz / (8 + 1)) = 2.8 MHz. Does the ADC need to run this
> slow, or did you not take the default division of CCLK by 4 into account?
>
I put the comment to say that I compute the CLKDIV to work with a
peripheral clock equal to cpu clock; this means that you could leave
PCLKSEL0 at 00 and modify CLKDIV to 2 or viceversa set relevant bits of
PCLKSEL0 to 01 and leave CLKDIV at 8. May be interesting compare adc
performance in the 2 situation, personally I didn't but may be a good
idea make a test.
> I see in the polling code you're continuously doing conversions until
> the done bit is set and the overrun bit is not set. Since I see the
> overrun bit set when the ADC has a misconversion, I can understand why
> you're doing this. However, the user's manual says that the overrun
> bit is only used in burst mode, which is not the case here. Is there
> something missing from the user's manual regarding overrun?
>
> The user's manual says this about the overrun bit:
>
> "This bit is 1 in burst mode if the results of one or more conversions
> was (were) lost and overwritten before the conversion that produced
> the result in the RESULT bits.This bit is cleared by reading this
> register."
>
> Since the bit is cleared by reading the data register, do you ever see
> it set, because wouldn't it be cleared when you read the data register
> to check the done bit in the body of the do while loop?
>
I test the overrun bit to give you a piece of code that may work in both
situations. What the manual doesn't say very clearly is that the overrun
bit will be set every time that the adc writes the corresponding data
register with a new data before the previous is read. The adc can
recognize the situation checking the DONE bit; if the DONE bit is set
and the adc writes a data in the data register means that the data
register wasn't read before then it sets the overrun bit, this is the
more general description. So, if we write a wrong function to read the
adc data register it is possible that the overrun bit may be set and
knowing that happens we know that we have to correct the software.

The worst error to find I saw on the LPC1xxx and LPC2xxx
microcontrollers was made using the general data register without
checking the read channel bits. The general register in my opinion is
very useful if you have to read adc data using interrupts, in this way
the function is simpler, but if you read the adc in polling mode it
isn't a good idea because you can't use both the general data register
and the channel data registers, you have to choose only one method.

The second worst error reading the adc is the wrong "shift and mask" order.
Using:
sample = ( (*pAdcData) >> 4) & 0x00000fff;
and choosing sample as an unsigned integer solves the problems related
to shift and mask.
If you have any doubt that your compiler may change the order of the
operations you could also to divide the operations in 2 instructions:
sample = ( (*pAdcData) >> 4);
sample &= 0x00000fff;
>



--- In l..., "M. Manca" wrote:
> The worst error to find I saw on the LPC1xxx and LPC2xxx
> microcontrollers was made using the general data register without
> checking the read channel bits. The general register in my opinion is
> very useful if you have to read adc data using interrupts, in this way
> the function is simpler, but if you read the adc in polling mode it
> isn't a good idea because you can't use both the general data register
> and the channel data registers, you have to choose only one method.
>
> The second worst error reading the adc is the wrong "shift and mask" order.
> Using:
> sample = ( (*pAdcData) >> 4) & 0x00000fff;
> and choosing sample as an unsigned integer solves the problems related
> to shift and mask.
> If you have any doubt that your compiler may change the order of the
> operations you could also to divide the operations in 2 instructions:
> sample = ( (*pAdcData) >> 4);
> sample &= 0x00000fff;

I implemented the changes you described in an earlier post last night and -- no change in the results. I'm still seeing random bad conversions throughout the 0-4095 range.

I tried increasing CLKDIV, thinking a slower ADC clock might improve things, but even when I cranked it up to 15 (for a divide by 16 of PBCLK), I didn't see any change in the frequency of bad conversions.

At this point, I'm going to start probing right at the MCU pins looking for noise and glitches on the analog inputs and references/grounds. I also have an LPCXpresso with a LPC1769 I'll try my code on.

Il 14/02/2012 20:44, Jerry ha scritto:
>
>
> --- In l... , "M.
> Manca" wrote:
> > The worst error to find I saw on the LPC1xxx and LPC2xxx
> > microcontrollers was made using the general data register without
> > checking the read channel bits. The general register in my opinion is
> > very useful if you have to read adc data using interrupts, in this way
> > the function is simpler, but if you read the adc in polling mode it
> > isn't a good idea because you can't use both the general data register
> > and the channel data registers, you have to choose only one method.
> >
> > The second worst error reading the adc is the wrong "shift and mask"
> order.
> > Using:
> > sample = ( (*pAdcData) >> 4) & 0x00000fff;
> > and choosing sample as an unsigned integer solves the problems related
> > to shift and mask.
> > If you have any doubt that your compiler may change the order of the
> > operations you could also to divide the operations in 2 instructions:
> > sample = ( (*pAdcData) >> 4);
> > sample &= 0x00000fff;
>
> I implemented the changes you described in an earlier post last night
> and -- no change in the results. I'm still seeing random bad
> conversions throughout the 0-4095 range.
>
> I tried increasing CLKDIV, thinking a slower ADC clock might improve
> things, but even when I cranked it up to 15 (for a divide by 16 of
> PBCLK), I didn't see any change in the frequency of bad conversions.
>
> At this point, I'm going to start probing right at the MCU pins
> looking for noise and glitches on the analog inputs and
> references/grounds. I also have an LPCXpresso with a LPC1769 I'll try
> my code on.
>
Until now I had problems only on mbed boards but is due to an unhappy
pcb design. On other development boards and on my own boards I have no
similar problems as yours. Thinking about the 4095 count I could say
that is as if your pin reads the VCC or the VREF or a voltage greater or
equal to VREF. So... just to speaking you could check VREF and its
ground pins and... check if there is the possibility that for any
strange reason your sw (think to a strange bug) may setup your analog
pin as a digital i/o during the conversion phase (I can't imagine the
result).
>