cancel
Showing results for 
Search instead for 
Did you mean: 

Multichannel ADC

muliku
Associate II
Posted on May 06, 2015 at 19:17

Hi, I'm developing application on STM32F0 where I use two gas sensors (CO and CO2), so I need two channels on ADC. In my main.c I only call two functions and on beginig of each function I change channel like so:

while(1){ 
CO(); 
CO2(); 
} 
void CO() 
{double ADC1ConvertedValue; 
ADC1->CHSELR |= ADC_CHSELR_CHSEL1; 
//AD conv. and sending data to usart
} 
void CO2() 
{double ADC1ConvertedValue; 
ADC1->CHSELR |= ADC_CHSELR_CHSEL4; 
//AD conv. and sending data to usart}

When I comment on of those two functions it runs just fine (CO gives me value around 750 and CO2 gives me value around 1000 until I blow into it or something). But when I uncomment both function and wanna measure both at once it gives me weird numbers, for example CO is 800 and in very next measurment it is 2500 and then back to 800. It seems like mcu cannot handle switching the channels or what. Can anyone explain where is the problem? I'm beginer at programming STM32 and I read something about DMA that it is best way to do it, but I didnt manage to make it functional. Will this switching of channel work or do I need to use another method? btw ADC1 conf. is below:

void ADC1_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
/* ADC1 DeInit */
ADC_DeInit(ADC1);
/* ADC1 Periph clock enable */
RCC->APB2ENR |= (1<<9);
/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);
/* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Wait the ADCEN falg */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
/* ADC1 regular Software Start Conv */
ADC_StartOfConversion(ADC1);
}

#adc #stm32f0 #no-hablo-hal #multichannel
10 REPLIES 10
Posted on May 06, 2015 at 19:27

Not using the F0, on others the use of DMA for multiple channels is the way to go.

I don't think just ORing bits without clearing/masking others is going to work.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
muliku
Associate II
Posted on May 06, 2015 at 20:10

so what should I do to avoid DMA? will this work with some adjustments?

Posted on May 06, 2015 at 22:00

so what should I do to avoid DMA? will this work with some adjustments?

I don't know, but it's going to start with you selecting a single channel, and not ORing a whole bunch of them, and not putting the device in continuous mode, but rather selecting a single channel, and starting a single conversion.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
muliku
Associate II
Posted on May 07, 2015 at 12:06

I don't think just ORing bits without clearing/masking others is going to work.

 

You were absolutely right. I just added turning off the channel before switching:

ADC1->CHSELR &= ~ADC_CHSELR_CHSEL1;

ADC1->CHSELR |= ADC_CHSELR_CHSEL4;

And it works just fine. Thanks
quang-vu
Associate II
Posted on May 12, 2016 at 09:05

How can i get stable value when i change channels ?

for example

void getvalue ( void )

{

 ADC1->CHSELR |= ADC_CHSELR_CHSEL3;

 value[0] = HAL_ADC_GetValue(&hadc);

  ADC1->CHSELR &= ~ADC_CHSELR_CHSEL3;

  ADC1->CHSELR |= ADC_CHSELR_CHSEL2;

  value[1] = HAL_ADC_GetValue(&hadc);

...

...

}

jay1991
Associate II
Posted on May 12, 2016 at 09:22

I have used two ADC channels ADC_channel_0 and ADC_channel_1. You can easily get the values by adding Delay between these two.

/* this will be in while loop*/
drive_Analog_Port_0();
Delay(50); 
drive_Analog_Port_1();
Delay(50); 
sprintf(str1, 
''c0: %4d, c1: %4d

''
,val0,val1 );
USART_puts(USART1, str1);
/* this will be declared out the Main */
void
drive_Analog_Port_0(
void
)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_144Cycles);
ADC_SoftwareStartConv(ADC1);
//Start the conversion
while
(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
//Processing the conversion
val0= ADC_GetConversionValue(ADC1);
}
void
drive_Analog_Port_1(
void
)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_144Cycles);
ADC_SoftwareStartConv(ADC1);
//Start the conversion
while
(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
//Processing the conversion
val1= ADC_GetConversionValue(ADC1);
}

You can easily getting this with the use of delay.
quang-vu
Associate II
Posted on May 12, 2016 at 15:05

Thank you. But i dont want to add HAL_Delay( ) between the instruction. Is it possible to do it without HAL_Delay( ) ?

Posted on May 12, 2016 at 17:12

Using Continuous mode for a single shot conversion seems like a poor strategy... Think I mentioned that earlier...

ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
quang-vu
Associate II
Posted on May 13, 2016 at 14:20

Hi

i use STM32F0 and try to get some data from ADC.

why do i get always wrong value when switching channel ? the ADC->DR shows me correct value just one time and next time only wrong value.

for example:

        ADC1->CHSELR |= ADC_CHSELR_CHSEL1;

         ai[0] = HAL_ADC_GetValue(&hadc);

          ADC1->CHSELR &= ~ADC_CHSELR_CHSEL1;  <----- turn off

          ADC1->CHSELR |= ADC_CHSELR_CHSEL2;

          ai[1] = HAL_ADC_GetValue(&hadc);

          ADC1->CHSELR &= ~ADC_CHSELR_CHSEL2;

how can i do it better ?