Faulty ADC readings when using DONE flag

Started by Kevin Townsend December 7, 2008
I've been trying to understand why I get faulty (i.e., very erratic)
readings from the ADC, with differences of 500 or 600 (on a 10-bit
scale) between readings. Even stranger is that when the ADC is not
connected to anything, I still get very odd readings all over the
map from the ADC.

Using the code from JC Wren's LPC2148 demo library, and discussing
it with him, I've isolated the problem to when I wait for the DONE
flag. When I comment out the code that waits for the done signal,
everything works exactly as I expect. I'm really not sure why I'm
getting this odd behaviour, though.

For reference sake, this is the code:

int adcRead0_3(void)
{
AD0_CR &= ~(AD_CR_START_MASK | AD_CR_SELMASK);
AD0_CR |= (AD_CR_START_NOW | AD_CR_SEL3);
AD0_CR |= AD_CR_START_NOW;

while (!(AD0_DR3 & AD_DR_DONE))
;

return ((AD0_DR3 & AD_DR_RESULTMASK) >> AD_DR_RESULTSHIFT);
}

//
// Assumes PCLK == 48Mhz
//
void adcInit(void)
{
PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P030_MASK) |
PCB_PINSEL1_P030_AD03;

SCB_PCONP |= SCB_PCONP_PCAD0;

AD0_CR = AD_CR_CLKS10 | AD_CR_PDN | ((11 - 1) <<
AD_CR_CLKDIVSHIFT) | AD_CR_SEL3;
}

U32 vTestTask(void)
{
U32 distance = 0;
char buf[10];
for (;;)
{
distance = adcRead0_3(); // maxSonar_Read();
// convert distance to string [buf]
itoa(distance, buf, 10);
debug_printf(buf);
debug_printf("\n");
}
}

And these are the relevant registers for adcRead0_3:

#define AD0_CR (*(pREG32 (0xe0034000)))
#define AD0_DR3 (*(pREG32 (0xe003401c)))
#define AD_CR_SEL3 (0x00000008)
#define AD_CR_SELMASK (0x000000ff)
#define AD_CR_START_NOW (0x01000000)
#define AD_CR_START_MASK (0x07000000)
#define AD_DR_DONE (0x80000000)
#define AD_DR_RESULTMASK (0x0000ffc0)
#define AD_DR_RESULTSHIFT (6)

By commenting out the while loop in adcRead0_3, it works well, but
then I risk accessing the ADC when the read isn't complete. Has any
one here had a similar problem/experience with the ADC?

Kevin.

An Engineer's Guide to the LPC2100 Series

I forgot to mention the platform. I'm using this on a 2148. I've
tested the code on 2 Olimex P2148 boards and 1 Olimex H2148 board,
as well as using two different analog devices ... all with the same
results.

I've also tested the ADC by connected it to GND and 3.3v,
consistently getting the expected 0 and 1023 values when the DONE
flag is commented out, but getting those same values intermingled
with other random values when the done loop is enabled.

Ex: With ADC0.3 connected to 3.3v:

512
512
1023
1023
1023
512
1023
1023
512
512
512
512
512

With ADC0.3 connected to GND:

0
0
0
0
0
0

With ADC0.3 connected to a device:

0
0
414
0
0
414
0
0
414
414

Kevin.