I think you mean by ''dynamic values'' that the signal you mesured is a variable signal. Please refer to this application note that describes methods to get the best ADC accuracy: ''How to get the best ADC accuracy in STM32F10xxx devices'' http://www.st.com/stonline/products/literature/an/15067.pdf B.R. M3allem
I have a problem with the ADC, if I read static values everything is fine, but dynamic values are wrong. parameter: µC: STM32F103RBT6 IAR KickStart Kit VDDA: 3,3 V VSSA: 0 V samplerate: 25,6 kHz signal: 1 V peak-to-peak 3kHz offset: 1,65 V at Pin PA5 = ADC5 correct values: Vmax: 2,15 V = 2668 Vmin: 1.15 V = 1427 my values: Vmax: 2200 Vmin: 1919
Code:
Clocks: /* RCC system reset(for debug purpose) -------------------------------------*/ RCC_DeInit(); /* Enable HSE --------------------------------------------------------------*/ RCC_HSEConfig(RCC_HSE_ON); /* Wait till HSE is ready --------------------------------------------------*/ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* Enable Prefetch Buffer ------------------------------------------------*/ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* Flash 2 wait state ----------------------------------------------------*/ FLASH_SetLatency(FLASH_Latency_2); /* HCLK = SYSCLK ^= 72 MHz -----------------------------------------------*/ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* PCLK2 = HCLK ^= 72 MHz ------------------------------------------------*/ RCC_PCLK2Config(RCC_HCLK_Div1); /* PCLK1 = HCLK/2 ^= 36 MHz ----------------------------------------------*/ RCC_PCLK1Config(RCC_HCLK_Div2); /* Configure ADCCLK such as ADCCLK = PCLK2/8 ^= 9 MHz -------------------*/ RCC_ADCCLKConfig(RCC_PCLK2_Div8); /* PLLCLK = 8MHz * 9 = 72 MHz --------------------------------------------*/ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* Enable PLL ------------------------------------------------------------*/ RCC_PLLCmd(ENABLE); /* Wait till PLL is ready ------------------------------------------------*/ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /* Select PLL as system clock source -------------------------------------*/ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* Wait till PLL is used as system clock source --------------------------*/ while(RCC_GetSYSCLKSource() != 0x08) { } } GPIO: /* GPIO Configuration ------------------------------------------------------*/ GPIO_InitTypeDef GPIO_InitStructure; /* Configure PA.05 (ADC Channel 5) as analog input -------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = (GPIOSpeed_TypeDef)0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC: ADC_InitTypeDef ADC_InitStructure; /* System clocks configuration ---------------------------------------------*/ /* Enable peripheral clocks ------------------------------------------------*/ /* Enable ADC1 and GPIOA clock ---------------------------------------------*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA , ENABLE); /* Reset the ADC register to their default reset values --------------------*/ ADC_DeInit(ADC1); /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); /* Enable ADC1 -------------------------------------------------------------*/ ADC_Cmd(ADC1, ENABLE); /* Enable ADC1 reset calibaration register ---------------------------------*/ ADC_ResetCalibration(ADC1); /* Check the end of ADC1 reset calibration register ------------------------*/ while(ADC_GetResetCalibrationStatus(ADC1) == SET); /* Start ADC1 calibaration -------------------------------------------------*/ ADC_StartCalibration(ADC1); /* Check the end of ADC1 calibration ---------------------------------------*/ while(ADC_GetCalibrationStatus(ADC1) == SET); Int16U GetADC1Channel(Int8U channel) { // Configure channel ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5); // Start the conversion ADC_SoftwareStartConvCmd(ADC1, ENABLE); // Wait until conversion completion while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // Get the conversion value return ADC_GetConversionValue(ADC1); }
I dont know if this is related but I am observing a strange problem at the time a new ADC channel is selected.
I am running continuous captures on 12 Channels (including the 2 internal channels vref, temp) with DMA, using the ST provided examples. The 4 analog inputs are each connected to an external 30K resistor pulling to ground and nothing else. With a voltmeters, I read around 40mV on the input pin. With the oscilloscope, I see a 100 to 300mV spike on the input pin. The spike IS GENERATED BY MCU. It is output at precisely the time that Analog input channel is selected. By putting the probe on the next input channel, I see a similar pulse that is precisely when the next channel is selected. In this case 3us later(36MHz + using ADC prescaller 2/4, and 5 cycles). See capture attached. Changing the ADC prescaller changes the period of the pulses. As a result, the ADC doesnt read exactly 0 on these inputs even though they are only connected to ground via a resistor. Connecting to ground with a wire causes the ADC to read 0. Has anyone else seen this? Is there a way to make the ADC wait a moment before starting the conversion? Thanks
What is your board exactly? If it's the KickStart board STM3210E-SK/IAR then PA.05 is connected to an LCD controller chip which could be interfering with your signal. If this is the board you have, have you been sure to disconnect this chip or take some other measures to ensure that this isn't happening?
The other issue I see is that there's nothing in your code that shows you're really sampling at 25.6KHz. The rate you supply to ADC_RegularChannelConfig (which you should only need to do once, by the way) determines how long a single conversion will take, but the actual sample rate will depend on how often you call this function. Of course, if you're calling it repeatedly in a loop without any delays in between then the result will be almost the same as continuous conversion, in which case you should probably just use that instead. If this is what you're doing then your effective sample rate would be close to 9MHz / (55.5 + 12.5) = 132.353KHz, which is not what you said the sample rate is. So it's important that we know the details of when and how you're calling this function. However, it'll still be better for you to either use continuous conversion (if your desired sample rate is high enough) or external trigger on the ADC supplied by a timer.
@M3allem: I have read the application note, but I can't find anything wrong. As I wrote, I use the KickStart Kit and connected a frequenz generator directly to the Pin. I also use an oscilloscope to check the signal at the Pin, and the signal is okay.
Thanks for the input. The errata I was able to find talks about a 10ns pulse of 150mV max on ADC0 only. What I see is much longer (almost 5us) and is on every channel with a 30K resistor to ground at the input.
See capture of ADC Ch2 input. In this case, I configured the ADC to capture Ch2 twice in a row. The spike can be seen at the start of both conversions. It is tied to conversion start and not channel switching, which makes workaround that much more difficult. Hopefully it is because of something I'm doing wrong but I fail to see what it could possibly be.
You're right. I took the errata reference out of memory and it wasn't the same issue. Then it's most likely (as aleh hinted) insufficient sampling time for your source resistance. Or rather, since your sampling time is maxed, simply too high source resistance. The solution is buffering high speed signals, and for low speed signals choose the capacitor in the RC-filter (which is a good thing to have anyway) large enough to overcome the effect of the sample-and-hold capacitor. It's about 5 pF so 10 nF would be well enough for most applications. [ This message was edited by: andreas1 on 22-07-2009 16:16 ]
On our channel 10 we had a 100K pull down resistor on the input. On channel 11 there was no pulldown R but a 100nF to ground. We realised that there would be a capacitor switching during the ADc sample in the ADC and the 100nF cap would compensate for this. Cosmapa - I suggest that you try a 100nF cap to ground on each ADC input, hopefully this should solve your problem.