2012-09-22 10:38 PM
I have stmf4discovery board with an LCD screen connected via FCMC. I've taken the ADC3_DMA StdPeriph example and adopted it to use PC1 pin since my board does not have PF7 (I hope it does not).
So, if I apply 3v from the board to the pin - the code shows stable precise 3300. Sweet. But why does it show approx 800 (value is changing all the time but it is about 800)? My multimeter shows zero voltage on the pin. Here are pieces of the code: void ADC3_CH11_DMA_Config(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable ADC3, DMA2 and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); /* DMA2 Stream0 channel2 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue; 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(DMA2_Stream0, &DMA_InitStructure); DMA_Cmd(DMA2_Stream0, ENABLE); /* Configure ADC3 Channel11 pin as analog input ******************************/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOC, &GPIO_InitStructure); /* ADC Common Init **********************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; 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(ADC3, &ADC_InitStructure); /* ADC3 regular channel11 configuration *************************************/ ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_3Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); /* Enable ADC3 DMA */ ADC_DMACmd(ADC3, ENABLE); /* Enable ADC3 */ ADC_Cmd(ADC3, ENABLE); } while (1) { ADC3ConvertedVoltage = getADC3ConvertedValue() *3300/0xFFF; char buffer[] = '' ''; int i; for(i=0;i<3000000;i++) { } LCD_DisplayStringLine(30, 72, buffer); // cleaning the space itoa(ADC3ConvertedVoltage, buffer); LCD_DisplayStringLine(30, 72, buffer); }2012-09-23 06:55 AM
Do you leave the AN pin floating in this case, or do you pull it down ?
In the first case, this means an almost infinite input resistance, so the analog circuitry is easily picking up internal and external noise. A pulldown of a few kOhm will bring down you reading to zero.2012-09-23 07:46 PM
''floating'' as not connected to anything and ''pull it down'' as ''grounded with a resistor''?
I was really hoping this world would be simple, digital and programmed in C, I guess I should gain more understanding of the analog side of things. I have tried a 2.5K (gives ''zero'' value under 0.005v) and a 5K (gives ''zero'' within 0.02v) resisters between the ADC pin and ground. While it did bring the value to nearly zero, this resistor is now affecting my input readings. I guess I should try higher resistance ''pull down''? And thank you for your response!2012-09-23 11:59 PM
Well, normally you have some source connected to the ADC input, with it's driving capability (or, to state it the other way around, it's inner resistance). Under normal circumstances, this is a buffer amplifier, which has often a gain of 1.
The effect you observed is one of the main purposes to use one. Even if it's input is 0 Volt, it is driving this 0 Volt actively, effectively discharging the S&H capacitor. With this resistor on the AN, this S&H capacitor 'unloads' the noisy charges it picked up, while the 3.3V source is surely capable to drive the current through this resistor and charge the S&H cap. For a practical application, you would not use a resistor at the ADC input, my suggestion was just to demonstrate the effect. > I was really hoping this world would be simple, digital and programmed in C, > I guess I should gain more understanding of the analog side of things. That is always an advantage...2013-01-25 09:43 PM
The buffer amplifier reference was a blessing - while trying to figure out which particular part number I should connect and how I have found this article - http://www.embeddedrelated.com/showarticle/php This has hinted me to increasing the ADC sampling time from 3 cycles to 480 cycles - and this made a HUGE difference, even with a 10k capacitor the ground reading is close enough to zero and 3.3 reading is close enough to 4 So this was all about charging the whatever capacitor which is inside.
I need to measure DC voltage which does not change fast, like 100 readings per second would be totally fine. Hopefully, in such a use case I do not really need the amplified and the increased sampling time will do the job? Anyway, now I am trying to change the single-channel code into a two-channel but something is still wrong - the code only returns proper value for the first channel. I am now initializing two pins and configuring two channels, also the buffer size was increased and ADC_NbrOfConversion. Still, what am I missing?#define ADC_CHANNEL_COUNT 2
__IO uint16_t ADC3ConvertedValue[2];
uint16_t getADC3ConvertedValue(int index) {
return ADC3ConvertedValue[index];
}
#define PAL_PORT_BIT(n) ((1 << (n)))
void configureAnalogPin(int pin) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure ADC pin as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = PAL_PORT_BIT(pin);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**
* @brief ADC3 with DMA configuration
*/
void initADC3_CH11_DMA_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* Enable ADC3 and DMA2 ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
/* Enable GPIO clock ****************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
/* DMA2 Stream0 channel2 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_2;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = ADC_CHANNEL_COUNT;
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(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE);
configureAnalogPin(1);
configureAnalogPin(2);
/* ADC Common Init **********************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
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 = ADC_CHANNEL_COUNT;
ADC_Init(ADC3, &ADC_InitStructure);
/* ADC3 regular channels configuration *************************************/
ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 2, ADC_SampleTime_480Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
/* Enable ADC3 DMA */
ADC_DMACmd(ADC3, ENABLE);
/* Enable ADC3 */
ADC_Cmd(ADC3, ENABLE);
ADC_SoftwareStartConv(ADC3);
}
2013-01-26 04:26 AM
There might be other issue, but these lines are needed DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue[0];
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
2013-01-26 05:26 AM
GPIO_InitStructure.GPIO_Pin = PAL_PORT_BIT(pin);
I can see only one GPIO being configured for AIN.
I think you need to add your second channel here, too.
2013-01-26 05:02 PM
I am invoking
configureAnalogPin
twice, so this part is probably fine.
2013-01-26 05:09 PM
&ADC3ConvertedValue[0]
and DMA_MemoryInc_Enable did not help :( While I am sure I am reading different array elements print(''adc 0 %d\r\n'', getADC3ConvertedValue(0)); print(''adc 1 %d\r\n'', getADC3ConvertedValue(1)); Looks like both array elements contain the value for channel 1