cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f4discovery, continues adc, noise

arro239
Associate III
Posted on August 08, 2013 at 05:14

I'm sorry, that's probably quite a beaten topic :(

I have continues mode ADC running on stm32f4discovery board.

static void ADC_Config(void) {
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADCx, DMA and GPIO clocks ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE);
RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
/* DMA2 Stream0 channel2 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_CHANNELx;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ADCx_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &uhADCxConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA_STREAMx, &DMA_InitStructure);
DMA_Cmd(DMA_STREAMx, ENABLE);
/* Configure ADC3 Channel7 pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIO_PORT, &GPIO_InitStructure);
/* ADC Common Init **********************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC3 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADCx, &ADC_InitStructure);
/* ADC3 regular channel7 configuration *************************************/
ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_480Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE);
/* Enable ADC3 DMA */
ADC_DMACmd(ADCx, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADCx, ENABLE);
print(''ADC_Cmd ENABLE\r\n'');
}

My board is powered via the mini-USB plus I have a UART-USB dongle connected to the same desktop. My ADC input is connected to a voltage divider made of two 150 ohm resistors between GND and 3V on the board. My loop prints values to console: while (1) { Delay(200); // 200 ms print(''ADC: %d\r\n'', uhADCxConvertedValue); } My question is about the noise. The values I see on the console are jumping in the 1957-1971 range, that's a 1% precision - that's a loss of 4 bits. I would like to reduce this noise. Unfortunately I am a software developer, not an electrical engineer. I've tried a 0.1uf capacitor between the ADC input and ground and this does not reduce the noise. As far as I know I do not have an option to use ''external reference voltage'' with this board unless I modify it. Other than digital filtering, could anything be done here? Would it help if I modify the board to provide external ADC reference voltage? Would you recommend switching to external ADC chip altogether? Is there another dev board I should look at?
6 REPLIES 6
Posted on August 08, 2013 at 09:04

You might want to have a look at AN4073: How to improve ADC accuracy when using STM32F2xx and STM32F4xx microcontrollers, http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00050879.pdf

JW
frankmeyer9
Associate II
Posted on August 08, 2013 at 09:14

I believe the discovery boards were designed with something else in mind, not the best ADC performance. Your noise figures are matching my experiences.

I think you need to approach a good hardware designer to improve that significantly. At the meantime, you could try SW filtering.

Posted on August 08, 2013 at 09:38

I'm afraid it won't help significantly. That's why I gave the link to AN4073 - their experiments were surely performed with good enough hardware setup (''STM32F407ZGT6 soldered on a test board (with only a minimum number of other hardware components)''), yet the raw data had a dispersion of around 20LSB...

Let's face it: it is nontrivial (read: next to impossible) to design a performing 12-bit ADC integrated on a low-cost general-purpose MCU/SoC. Those, who do, are marketed as such (premium price included).

JW

arro239
Associate III
Posted on August 08, 2013 at 13:46

If I am at the edge of what could be achieved using the dev board, would it be simpler to get higher precision on a dedicated external ADC chip? Obviously I would not be able to transfer 1M/sec of measurement results over SPI, bu that's fine.

If an external ADC is an option, I would appreciate hints on which particular chip would make me happy.

John F.
Senior
Posted on August 08, 2013 at 14:58

They may not make you happy but have a look at Linear Technology ADCs LTC2360/LTC2361/LTC2362. You can connect these to SPI.

v_
Associate II
Posted on August 12, 2013 at 13:43

Andrey,

The solution of your problem does not need to be a different hardware! The noise you're discovering is to a big portion probably ''random'' noise (i. e. non synchronous with the conversion process). Naturally you may reduce HF noise of all kind by a low pass filter (your C in parallel would be one if you would add a serial R) but random noise can be ''filtered'' out much more efficiently by a process called ''averaging''. Instead of sleeping 200 ms in your main loop you could simply take and add up 64 k of samples (need to be summed up into a 32bit integer) and finally right shift the result by 16 (i.e. calculating the mean). This would reduce your random noise by magnitudes and leave you just with synchronous noise, offset errors and non-linearity errors. Offset and non-linearity may be ''calculated out'' of your results by means of a calibration curve. Synchronous noise is the only difficulty you may not really get rid of by software. One solution is to reduce any high frequent bus activity during conversion. So if you really do pause in a sleeping loop as you do right now, there should be no activity on the GPIO pins beside the analog signal you're interest in. Therefore there should be no trouble with synchronous internal system noise. If you add code to your example which does trigger external GPIO traffic (e.g. any SPI or CAN or UART) then try to avoid such bus traffic during ADC conversions.

Hope that helps... And try this first before you go and redesign your hardware!