cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple ADC STM32F303 discovery board

marko
Associate II
Posted on July 09, 2013 at 23:45

The original post was too long to process during our migration. Please click on the attachment to read the original post.
10 REPLIES 10
Posted on July 11, 2013 at 01:22

A blind stab at fixing your incomplete code. Might dig out the STM32F3-Discovery later.

volatile unsigned short ADC_Values[3]; // Changed outside program flow
unsigned short adc_pin0;
unsigned short adc_pin1;
unsigned short adc_pin3;
int main(void)
{
/* Configure the ADC clock
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);
/* Enable ADC1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
/* Setup SysTick Timer for 1 µsec interrupts */
if (SysTick_Config(SystemCoreClock / 1000000))
{
/* Capture error */
while (1)
{}
}
/*** DMA ***/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_InitStructure.DMA_BufferSize = 3;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Values[0];
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // unsigned short - 16-bit
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
LED_On_color(GREEN);
/* ADC Channel configuration */
/* GPIOC Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
/* Configure ADC Channel 6,7 and 9 as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
ADC_StructInit(&ADC_InitStructure);
/* Calibration procedure */ 
ADC_VoltageRegulatorCmd(ADC1, ENABLE);
/* Insert delay equal to 10 µs */
Delay(10);
ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) != RESET);
calibration_value = ADC_GetCalibrationValue(ADC1);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; 
ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode; 
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; 
ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot; 
ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0; 
ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0; 
ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable; 
ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable; 
ADC_InitStructure.ADC_NbrOfRegChannel = 3;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel 6,7 and 9 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_7Cycles5); // PC.0
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_7Cycles5); // PC.1
ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 3, ADC_SampleTime_7Cycles5); // PC.3 
// DMA_ITConfig( DMA1_Channel1, DMA_IT_TC, ENABLE ); // Let's not
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
// ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); // Let's not
// NVIC_SetPriority(ADC1_2_IRQn, 0);
// NVIC_EnableIRQ(ADC1_2_IRQn);
ADC_GetConversionValue(ADC1);
/* Start ADC1 Software Conversion */
ADC_StartConversion(ADC1); 
/* Infinite loop */
while (1)
{
adc_pin0 = ADC_Values[0];
adc_pin1 = ADC_Values[1];
adc_pin3 = ADC_Values[2];
}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
marko
Associate II
Posted on July 12, 2013 at 20:43

Thanks it works now perfectly.

acortes
Associate II
Posted on October 09, 2015 at 09:28

Hello,

This works perfectly but only one time. I thought that the following configuration ''ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;'' means that the ADC is converting continuosly or that is the theory. If I use only the ADC (without DMA) and one channel, it works, that is, it converts continuosly.

However, I need to convert some analog channels continuosly using DMA and I do not achieve my purpose. Furthermore, I need to know when the ADC and DMA have finished a complete transfer. Then, I have added DMA interrupts or ADC interrupts but I achieve the same, only one transfer.

Some suggestion?

Thank you very much in advance.

AvaTar
Lead
Posted on October 09, 2015 at 13:07

When using the ADC in continuous mode, you don't necessarily need DMA.

You can use the EOS (EndOfSequence interrupt instead). Otherwise, use the DMA in circular mode, not single-shot as in your code:

ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot; 

acortes
Associate II
Posted on October 13, 2015 at 11:50

Yes, I know that it is not required to use DMA but I think this will be better in terms of time....I have used the Circular Mode and it doesn't work...

Anyway, if I use the EOS interrupt instead of DMA, how can I access to each converted values of the different channels? If I do something like this in the IRQHandler?

        ADC_ClearITPendingBit(ADC1, ADC_IT_EOS);

        ADC1ConvertedValue[0] =ADC_GetConversionValue(ADC1);

        ADC1ConvertedValue[1] =ADC_GetConversionValue(ADC1);

        ADC1ConvertedValue[2] =ADC_GetConversionValue(ADC1);

AvaTar
Lead
Posted on October 14, 2015 at 09:26

You still need to pick up each value within the EOC interrupt when you use several channels of the same ADC. In difference to other vendor's devices, the STM32 does not employ a FIFO of channel-wise result registers.

But using the the EOS interrupt,  you are able to detect when you are finished with one set of values from each channel.

>I have used the Circular Mode and it doesn't work...

 

This must be a problem with your code - there do exist working examples.

But admittedly, ST's DMA initialisation and usage is not trivial, and the reference manual is not an easy read.

acortes
Associate II
Posted on October 14, 2015 at 11:51

Thank you for your response.

My aim is to convert 3 analog signals using 3 channels of ADC1. This code works one time, but I want to convert the signals continuosly. I'm using Nucleo-F334R8 board. This is the code that I am using. 

#include ''stm32f30x.h''

#include ''stm32f3xx_nucleo.h''

#define ARRAYSIZE 3

volatile uint32_t status = 0;

volatile uint32_t i;

volatile unsigned short ADC_Val[ARRAYSIZE];

NVIC_InitTypeDef NVIC_InitStructure;

//create DMA structure

DMA_InitTypeDef  DMA_InitStructure;

ADC_InitTypeDef         ADC_InitStructure;

ADC_CommonInitTypeDef   ADC_CommonInitStructure;

GPIO_InitTypeDef        GPIO_InitStructure;

int main(void)

{

RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);

/* Enable GPIO Clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

/* Enable DMA1 */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/* Enable ADC1 Clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);

/* Enable the DMA gloabal Interrupt */

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

DMA_DeInit(DMA1_Channel1);

DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Val[0];

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

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

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_Init(DMA1_Channel1, &DMA_InitStructure);

// Enable DMA1 Channel Transfer Complete interrupt

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3;//PC 0, 1, 3 

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  ADC_StructInit(&ADC_InitStructure);

  /* Calibration procedure */

  ADC_VoltageRegulatorCmd(ADC1, ENABLE);

  ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);

  ADC_StartCalibration(ADC1);

  while(ADC_GetCalibrationStatus(ADC1) != RESET );

  

  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

  ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;

  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

  ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;

  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;

  ADC_CommonInit(ADC1, &ADC_CommonInitStructure);

  ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;

  //ADC_InitStructure.ADC_ScanConvMode = ENABLE;//the ScanConvMode does not exist in the library I am using

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;

  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;

  ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;

  ADC_InitStructure.ADC_NbrOfRegChannel = ARRAYSIZE;

  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel 6, 7 & 9 configuration */

  ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_181Cycles5); //PC0

  ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_181Cycles5); //PC1

  ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 3, ADC_SampleTime_181Cycles5); //PC3

  DMA_Cmd(DMA1_Channel1, ENABLE);

 

 ADC_DMACmd(ADC1, ENABLE);

  /* Enable ADC1 */

  ADC_Cmd(ADC1, ENABLE);

  ADC_GetConversionValue(ADC1);

  /* wait for ADRDY */

  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));

  ADC_StartConversion(ADC1);

 

while (1)

  {

    //interrupts does the job

  }

}

void DMA1_Channel1_IRQHandler(void)

{

  //Test on DMA1 Channel1 Transfer Complete interrupt

  if(DMA_GetITStatus(DMA1_IT_TC1))

  {

      //status=1;

   //Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits

    DMA_ClearITPendingBit(DMA1_IT_GL1);

    DMA_ClearITPendingBit(DMA1_IT_TC1);

  }

Some suggestion? Something wrong?

Again, thank you very much for your feedback.

AvaTar
Lead
Posted on October 14, 2015 at 15:06

My code is based on the SPL V1.0.1 for the F30x, not sure if that fits for the F334 on your Nucleo board.

However, I think a call to ADC_DMAConfig() is missing:

...
ADC_RegularChannelConfig (ADC1, ADC_Channel_4, 2, ADC_SampleTime_181Cycles5);
ADC_DMAConfig (ADC1, ADC_DMAMode_Circular); /* Configure ADC DMA */
ADC_DMACmd (ADC1, ENABLE); /* Enable ADC DMA */
ADC_Cmd (ADC1, ENABLE); /* Enable ADC1 */
while (!ADC_GetFlagStatus (ADC1, ADC_FLAG_RDY)); /* wait for ADRDY */
...

I mean the call to ADC_DMAConfig (ADC1,

ADC_DMAMode_Circular

); BTW, when posting source code, you can employ the ''Format Source Code'' tool in the upper left corner of the toolbar (looking like a broad brush).
acortes
Associate II
Posted on October 14, 2015 at 16:03

Thank you very much!!!

Your contribution have been very helpful. I thought that with

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

, the DMA was working in circular mode but not...

The new configuration is working perfectly:

.....

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Val[0]; 

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 

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

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 

DMA_InitStructure.DMA_Priority = DMA_Priority_High; 

DMA_Init(DMA1_Channel1, &DMA_InitStructure); 

// Enable DMA1 Channel Transfer Complete interrupt 

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); 

/* GPIOC Periph clock enable */ 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3;//PC 0, 1, 3 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; 

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; 

GPIO_Init(GPIOC, &GPIO_InitStructure); 

 ADC_StructInit(&ADC_InitStructure); 

/* Calibration procedure */ 

ADC_VoltageRegulatorCmd(ADC1, ENABLE); 

ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);

ADC_StartCalibration(ADC1); 

while(ADC_GetCalibrationStatus(ADC1) != RESET ); 

 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;

ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;

 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;

 ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot;

 ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0; 

ADC_CommonInit(ADC1, &ADC_CommonInitStructure); 

ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;

ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

 ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;

 ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None; 

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

 ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;

 ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;

 ADC_InitStructure.ADC_NbrOfRegChannel = ARRAYSIZE;

 ADC_Init(ADC1, &ADC_InitStructure); 

/* ADC1 regular channel 6, 7 & 9 configuration*/

 ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_601Cycles5); //PC0 

ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_601Cycles5); //PC1

 ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 3, ADC_SampleTime_601Cycles5); //PC3

 DMA_Cmd(DMA1_Channel1, ENABLE); 

ADC_DMAConfig (ADC1, ADC_DMAMode_Circular); 

ADC_DMACmd(ADC1, ENABLE);

 /* Enable ADC1 */ 

ADC_Cmd(ADC1, ENABLE); 

ADC_GetConversionValue(ADC1); 

/* wait for ADRDY */ 

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY)); ......