cancel
Showing results for 
Search instead for 
Did you mean: 

Multi Channel ADC reading.

to_sam_kim
Associate II
Posted on September 14, 2013 at 02:04

Hello,

I tried to read two analog inputs from PA3(ADC1_IN3) and PA5(ADC1_IN5).

I expected tmpADC[0] has the input data of PA3 and tmpADC[1] has the input data of PA5. However, both tmpADC[0] and tmpADC[1] always have the input data of PA3. 

I read reference manual multiple times, but I couldn't figure out what is wrong.

Please let me know what is problem. I attached my code below(only ADC part).

Thanks 

&sharpinclude <stm32f4xx.h>

void ADC_Init(void)

{

 GPIOA->MODER   |= (3UL<<6)|(3UL<<10);     /*Set PA3 as an analog input, ADC1_IN3, Set PA5 as an analog input ADC1_IN5*/

 GPIOA->PUPDR   &= ~((3UL<<6)|(3UL<<10));   /*No Pull up and down resistor*/

 

 RCC->APB2ENR   =(1<<8);       /*ADC1 clk enable*/

 ADC1->CR1 = 0;

 ADC1->CR2 = (1UL<<0)|          /*ADC1 power on */

            (1UL<<1);          /*Continuous conversion*/

                     

 ADC1->SMPR1 = 0;

 ADC1->SMPR2 = 0;

 ADC1->SQR1 = (1<<20);                   /* sequence length: two regular conversions*/

 ADC1->SQR2 = 0;

 ADC1->SQR3 = (3UL<<0)|(5UL<<5);         /*1st conversion = ADC1_lN3, 2nd conversion = ADC1_IN5*/

 ADC->CCR = (1UL<<16);          /*fpclk2/4 = 21Mhz */

}

 

short unsigned int get_ADC(void)

{

ADC1->CR2 |= (1<<30);

 while(!(ADC1->SR & 0x2));

 return ADC1->DR;

}

int main (void)

{

       tmpADC[0]  = get_ADC();    // expecting have data from ADC1_IN3

  

       tmpADC[1] = get_ADC();   //expecting have data from ADC1_IN5

}

#stm32f4 #discovery-board #adc-dma
17 REPLIES 17
Posted on September 14, 2013 at 02:41

You'll want to be using DMA

Something like this should suffice

// STM32F2/4 Two Channel ADC1 Loop - sourcer32@gmail.com
#include <
stdio.h
>
#include <
stdlib.h
>
#include <
string.h
>
#include ''stm32f4xx.h''
//******************************************************************************
volatile uint16_t ADCConvertedValues[2];
//******************************************************************************
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Configure ADC1 Channel3 & 5 pins as analog input ******************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//******************************************************************************
void ADC1_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* Enable peripheral clocks *************************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* DMA2_Stream0 channel0 configuration **************************************/
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 2;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
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);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
/* 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);
/* ADC1 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
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 = 2;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel configuration ******************************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_480Cycles); // PA3
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_480Cycles); // PA5
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 **************************************************************/
ADC_Cmd(ADC1, ENABLE);
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
}
//******************************************************************************
int main(void)
{
GPIO_Configuration();
ADC1_Configuration();
puts(''ADC Testing'');
while(1)
{
if (ADCConvertedValues[1] != 0xFFFF)
{
printf(''%03X %03
X'', ADCConvertedValues[0], ADCConvertedValues[1]);
ADCConvertedValues[1] = 0xFFFF;
}
}
while(1); /* Infinite loop */
}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
to_sam_kim
Associate II
Posted on September 25, 2013 at 18:42

Thank you for the reply.

I'm studying DMA setup now with over 1000 pages reference manual..

By the way, DMA should be used in order to read multi channels of ADC input??

Thanks again,

Posted on September 25, 2013 at 18:53

By the way, DMA should be used in order to read multi channels of ADC input??

It's the prescribed method, for slow speed you might be able to service the EOC
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
to_sam_kim
Associate II
Posted on October 03, 2013 at 00:41

Yes, I figured out both way, using DMA and EOC multi channel ADC reading.

I couldn't make it work without your help.

Thanks again.

I attached my code for someone who has similar questions even if I 'm really entry level.

this code does blinking LD4 every 1sec withtime2 interrupt, control brightness of LD3with timer4 of PWM mode based on ADC1_In3 input, and turn on and off of LD5 and LD6 depending on ADC1_In5 input.

________________

Attachments :

ADC_DMA.c : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HzsV&d=%2Fa%2F0X0000000bRZ%2FaUcuuCv4EfDTsTtyPEt52e8TTUxbSI72CqhLNT9BQ6M&asPdf=false
Posted on October 03, 2013 at 00:57

The TIM SR register is cleared with a single write, not a read-modify-write (&=)

TIM2->SR = ~1;   // Clear flag

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
to_sam_kim
Associate II
Posted on October 03, 2013 at 18:16

Thank you for the comment for the mistake.

csfarnham
Associate II
Posted on October 08, 2013 at 02:40

I'm trying to achieve a four channel adc with dma.  I used the code that clive1 provided but I'm getting the following issues:

Values only on the first 2 elements of the array (All four ports are connected to the same voltage).

I'm getting values larger than 12-bits in the elements.

Here's the my set-up code below.  Any thoughts?

Thanks,

Chris

GPIO_InitTypeDef GPIO_InitStructure;

ADC_InitTypeDef ADC_InitStructure;

ADC_CommonInitTypeDef ADC_CommonInitStructure;

DMA_InitTypeDef DMA_InitStructure;

//#define ADC1_DR_ADDRESS     ((uint32_t)0x4001204C)

volatile uint16_t ADCConvertedValues[4] = {0,0,0,0};

void startUp(void)

{

//ADC Pins

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOA, &GPIO_InitStructure);

DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStructure.DMA_BufferSize = 4;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_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);

//ADCs

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);

ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStructure.ADC_ScanConvMode = ENABLE;

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

ADC_InitStructure.ADC_ExternalTrigConv = 0;

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructure.ADC_NbrOfConversion = 4;

ADC_Init(ADC1, &ADC_InitStructure);

ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_480Cycles);

ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 2, ADC_SampleTime_480Cycles);

ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 3, ADC_SampleTime_480Cycles);

ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 4, ADC_SampleTime_480Cycles);

ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

ADC_DMACmd(ADC1, ENABLE);

ADC_Cmd(ADC1, ENABLE);

ADC_SoftwareStartConv(ADC1);

}

 

Posted on October 08, 2013 at 03:04

I'm not sure those are particularly good pin choices for the STM32F4-Discovery board.

Might I suggest:

PA1 Ch1

PA2 Ch2

PA3 Ch3

PB0 Ch8

PB1 Ch9

PC1 Ch11

PC2 Ch12

PC4 Ch14

PC5 Ch15
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
csfarnham
Associate II
Posted on October 08, 2013 at 05:06

Thank you for the prompt reply.  I plan on using the rmii ethernet feature so some of those pins will be blocked.  I tried using PA3, PB0, PB1, PC2 and I'm still getting the same issue.  Only one pin is connected and I only see values for the first two elements of my array and they are giving me values >2^12.  Is this some sort of memory issue perhaps?

Thanks