cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L1: ADC ''generates'' signal?

Posted on July 03, 2014 at 17:22

After I discovered finally managed to get the ADC and DMA to run and play well together I ran into a very strange problem:

While checking the results of my AD conversions in the debugger, I realised that the values must be off. Even when measuring the VREFINT channel, I got a value that was too high and the VDDA I calculated from this value was therefore about 0.5V(!) too low! So I pulled out an oscilloscope to check what happens. After a long time trying to isolate the problem, I realised that the ADC ''generates a triangular signal''. This ''signal'' corresponds to the conversion time. At the lowest conversion time, the signal has an offset of around 600mV(!) and an amplitude of around 20mV, while at higher conversion times, the offset is lower (down to about 60mV) and the amplitude higher (up to around 60mV). The period of the signal corresponds exactly to the configured cycle time + delay time. This seems to happen independently of the channel measured. The phenomenon is observable about as soon as the AD starts conversion (SWSTART bit set) and stops as soon as the conversion ends (SQRx reg written to). Although in my example I do continuous conversions, it appears to happen with single conversions and scan conversions as well. Did anyone ever encounter this phenomenon? Does anyone have an idea where this problem may come from? In the following (IAR!) code, which I used to test this phenomenon, I marked the lines with SWSTART and SQRx written to:


int main()

{

RCC_AHBENR_bit.GPIOAEN = 1;

RCC_AHBENR_bit.GPIOBEN = 1;


GPIOB_PUPDR_bit.PUPDR1 = 0;

GPIOB_MODER_bit.MODER0 = 3;

GPIOB_OTYPER_bit.OT0 = 0;


if (RCC_CR_bit.HSION == 0)

{

while (PWR_CSR_bit.VOSF)

{

/* wait for stable voltage range */

}


// set voltage range.

PWR_CR_bit.VOS = 1;

while (PWR_CSR_bit.VOSF)

{

/* wait for stable voltage range */

}


// HSI 16MHz oscillator on

RCC_CR_bit.HSION = 1;

while (!RCC_CR_bit.HSIRDY)

{

// wait until HSI is stable

}

}


if (!RCC_CFGR_bit.SW)

{

RCC_CFGR_bit.SW = 1;

}


while (1)

{

/* enable peripheral clock */

RCC_APB2ENR_bit.ADC1EN = 1;


/* prescaler for ADCCLK */

ADC_CCR_bit.ADCPRE = 0;


/* set ADC Resolution */

ADC_CR1_bit.RES = 0;


/* right alignment of result */

ADC_CR2_bit.ALIGN = 0;


/* set conversion time via cycles register */

ADC_SMPR3_bit.SMP9 = 0;


/* delay after conversion => no delay */

ADC_CR2_bit.DELS = 0;


/* overrun interrupt enable */

ADC_CR1_bit.OVRIE = 1;

SETENA0_bit.ADC1 = 1;


/* which channel to sample */

ADC_SQR5_bit.SQ1 = 9;

ADC_SQR1_bit.L = 0;


if (!ADC_SR_bit.ADONS)

{

/* ADC not running; power up the adc module */

ADC_CR2_bit.ADON = 1;


while (!ADC_SR_bit.ADONS)

{

/* wait until the adc is ready */

}

}


while (ADC_SR_bit.RCNR);

{

/* Wait for regular channel ready */

}


ADC_CR2_bit.CONT = 1;

ADC_CR2_bit.SWSTART = 1;


for (uint32_t i=0; i < 1024*1024; i++);


ADC_SQR5 = 0;


ADC_CR2_bit.ADON = 0;


while (ADC_SR_bit.ADONS)

{

/* wait until the adc is ready */

} // reset ADC registers. Required? Not really documented.

RCC_APB2RSTR_bit.ADC1RST = 1;

/* Release reset */

RCC_APB2RSTR_bit.ADC1RST = 0;


// disable peripherial clock

RCC_APB2ENR_bit.ADC1EN = 0;


}

return 0; // never reached

}

Please excuse the formatting; I did kind of copy/paste it from my actual driver code...
5 REPLIES 5
Danish1
Lead II
Posted on July 03, 2014 at 18:48

Every time the ADC makes a conversion, the first thing it does is it connects an internal capacitor to the pin, and charges up the capacitor with your input voltage. This capacitor is connected for the ''sampling time'' of your ADC conversion.

Once the capacitor is charged up, it is then disconnected from the input pin and the voltage on the capacitor is measured.

You should not be surprised to see some ripple if you have a high impedance source. But you should engineer the sampling time so that the sampling capacitor can charge with sufficient accuracy to the input voltage.

If your source impedance is too high, and your sampling time too short, then the capacitor will never charge up to the nominal voltage on the pin. If you must have a fast sampling time then you might need to buffer your analog voltage with an external op-amp.

Hope this helps,

Danish

Posted on July 04, 2014 at 09:10

The ''ripple'' I described is rather big, though. Even when configuring a sampling time of 384 cycles (+ the 12 for the resolution) I get a significant enough ripple (about 2% of full range) and it looks more like a capacitor discharching than a capacitor charging.

Thanks anyway. I will do some more research and try to see what causes this problem.

Danish1
Lead II
Posted on July 04, 2014 at 11:09

Another possibility is that your VddA is drooping.

The ADC draws power from the VddA line all the time it is making a conversion.

How do you power your VddA pin?

If you wire it directly to all your other (digital) Vdd pins then yes you will get electrical noise from the rest of the microcontroller feeding into your ADC reading.

A temptation is to low-pass filter from the digital Vdd pins (and equally the Vss pins) but if you choose a long time-constant (to filter out even lower-frequency noise) and achieve it with a high resistor and small capacitor then the voltage on VddA will droop as soon as you start a conversion.

Are you using a commercial demo board (if so which one) or something of your own design (in which case double-check your calculations).

When I need good performance from the ADC I have a second voltage regulator dedicated solely to VddA and any analog-signal-conditioning op-amps - and a good one at that (one with a fast frequency response).

 - Danish

Posted on July 04, 2014 at 11:15

What really irritates me as well is that if I measure VREFINT with the above setup; I get a difference of about 257 in ADC values (at 12bit) between measuring for 4 cycles vs. measuring for 384 cycles. I understand that longer conversion time delivers greater accuracy, but I did not expect it to be so far off!

For VREFINT, to get an acceptable result I need to configure a 96 cycles (+ the 12 for the resolution) to get an acceptable value. When measuring an external input, even at 384 cycles, I'm off significantly.

The main problem is that I see a voltage offset for as long as the conversion takes, but I don't get why and where this is coming from. The ramp signal currently doesn't bother me too much as it is rather small...

Posted on July 04, 2014 at 13:05

VDDA seems to be stable when converting. I have a custom design that someone else did. Between VDD and VDDA there is just a coil. No separate regulator.

As I mentioned, what mainly irritates me is the voltage offset that appears while converting, which is huge. Depending on the ADC channel (and thus, I assume depending on the input circuitry), it may be as high as 1.3V (when the pin is not connected to anything - no matter if internal pull-ups / pull-downs are activated or not).