2015-07-06 05:20 AM
hi everybody!
I'm developing on st32f0 a device with two analogics sensors. After the initialization, I can read properly one value but the other is always at it s maximum value (4095 for 12 bits of data). I can see my bad values in co2_value or temp_value. Do someone know where my problem is from. Thank you a lot.void ADC1_Config(void)
{ ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* GPIOB Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
/* ADC1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Configure ADC Channel11 as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* ADC1 Configuration *******************************************************/
/* ADCs DeInit */
ADC_DeInit(ADC1);
/* Configure the ADC1 in continous mode with a resolutuion equal to 8 bits*/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Backward;
ADC_Init(ADC1, &ADC_InitStructure);
/* Convert the ADC1 Channel 11 with 5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_8 , ADC_SampleTime_71_5Cycles);
ADC_ChannelConfig(ADC1, ADC_Channel_9 , ADC_SampleTime_71_5Cycles);
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);
/* Enable the auto delay feature */
ADC_WaitModeCmd(ADC1, ENABLE);
/* Enable the Auto power off mode */
ADC_AutoPowerOffCmd(ADC1, ENABLE);
/* Enable ADCperipheral[PerIdx] */
ADC_Cmd(ADC1, ENABLE);
/* Wait the ADCEN falg */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
ADC_StartOfConversion(ADC1);
float read_temp()
{
uint32_t calibration;
float temp_value[SAMPLES];
float volt_value=-1;
float intern_value=-1;
float intern_volt_value=-1;
float tempconv=-1;
int overrun=0;
int releve=0;
float temperature=-1;
ADC_StartOfConversion(ADC1);
delay_10_us();
int i;
for(i=0;i<SAMPLES;i++)
{
delay_ms(100);
temp_value[i]=ADC_GetConversionValue(ADC1);
}
for(i=0;i<SAMPLES;i++){
if(i%2==1)
{
releve++;
tempconv=tempconv+temp_value[i];
}
}
tempconv=tempconv/releve;
volt_value=(tempconv*2.978)/4095;
calibration=ADC_GetCalibrationFactor(ADC1);
temperature=volt_value*126742-772;
ADC_StopOfConversion(ADC1);
return temperature;
}
float read_co2()
{
uint32_t calibration;
float co2_value[SAMPLES];
float volt_value=-1;
float intern_value=-1;
float intern_volt_value=-1;
float co2conv=-1;
int overrun=0;
int releve=0;
float co2=-1;
ADC_StartOfConversion(ADC1);
delay_10_us();
int i;
for(i=0;i<SAMPLES;i++){
delay_ms(100);
co2_value[i]=ADC_GetConversionValue(ADC1);
}
for(i=0;i<SAMPLES;i++){
if(i%2==0)
{
releve++;
co2conv=co2conv+co2_value[i];
}
}
co2conv=co2conv/releve;
volt_value=(co2conv*2.978)/4095;
calibration=ADC_GetCalibrationFactor(ADC1);
co2=volt_value*2000/2;
ADC_StopOfConversion(ADC1);
return co2;
}
2015-07-06 06:43 AM
Here is a quote from the ADC library function adc.c
/*** @brief Stop the on going conversions for the selected ADC.
* @note When ADSTP is set, any on going conversion is aborted, and the ADC
* data register is not updated with current conversion.
* @param ADCx: where x can be 1 to select the ADC1 peripheral.
* @retval None
*/
void ADC_StopOfConversion(ADC_TypeDef* ADCx) It is possible to initialize and configure, then deinitialize the ADC twice to convert two values, but this is cumbersome. As Clive1 suggested, using DMA is the recommended approach. Cheers, Hal
2015-07-06 06:45 AM
Are you sure you can handle them individually like this? Or do you need DMA to scan between multiple channels.
2015-07-06 06:50 AM
2015-07-07 12:33 AM
Hi clive, thank you for your answer.
I will initialize the DMA butfor me it will not fix my problem.Indeed, when I begin a conversion, it will find this incoherent value 50% of the time..Don't you agree?2015-07-07 08:50 AM
If you read both values into memory in a continuous fashion, and one of them is constantly wrong you need to start looking at the hardware. Are you using the right pin? Is the signal suitable to stick directly into the sampling capacitor at the ADC? Is the rate of change too high? Is there sufficient current to charge/discharge the capacitor? Do you need an opamp/buffer on the signal?
Do the pins sample correctly if you just look at them individually?I have very little insight into your design.2015-07-07 03:21 PM
The F0 ADC is different from most of the ST line in that the number of channels converted is determined by the number of channels configured. The ADC here is set in continuous conversion mode to sample two channels, so it is continually overwriting the ADC data register with alternating channel 9 and 8 conversion results. Which result is read each time after the milliseconds of time delay is a matter of chance, in this case, 50% are the other channel.
With DMA initialized to a buffer size of 2, only one ADC start is required, no ADC stop is required, and the DMA storing the converted values should ping pong correctly between the two buffer locations. The results can be read at the program's leisure. Cheers, Hal