cancel
Showing results for 
Search instead for 
Did you mean: 

Multichannel ADC in disc. Mode (with DMA support)

jogerh
Associate II
Posted on July 14, 2015 at 17:00

Dear Community,

I want to use DMA to multichannel-convert the result of the ADC (for my case of the ADC1 of a F051 device). As shown in the STPL examples for the continuous mode this works very well. However I want to convert the ADC value(s) at a certain point in time since I have to setup some other parameters of my device first. I was thinking to configure the DMA and the ADC as shown in the examples but to use the DMA in normal-mode and the ADC in discontinues mode instead. Then I was thinking to start ADC conversion at some point in time and wait until either EOC is RESET or maybe DMA_IT_TC is set (which I probably need to clear if used). However unfortunately the whole concept does not work because I just get a zero as the result of the conversion. Therefore I want to ask whether my planed approach is possible or not. Here is some code (for the case I made a mistake somewhere). I would be very happy if someone would check this code for mistakes (if present).

unsigned char ConvADC0_ADC1[2]; 
void ADC_Config(void) 
{ 
ADC_InitTypeDef ADC_InitStructure; 
GPIO_InitTypeDef GPIO_InitStructure; 
DMA_InitTypeDef DMA_InitStructure; 
//ADC1 de-Init 
ADC_DeInit(ADC1); 
//DMY1 Clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE); 
//GPIO Periph Clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); 
//ADC1 Periph clock enable 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
//GPIO Config for ADC 
// Configure ADC Channel0 -> OSC Amp as analog input 
// Configure ADC Channel1 -> Temp 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(GPIOA, &GPIO_InitStructure); 
// Initialize ADC structure 
ADC_StructInit(&ADC_InitStructure); 
// Configure the ADC1 in continuous mode with a resolution equal to 8bits 
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;// 
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //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); 
// Convert the ADC1 Channel 0 and 1 with 5 Cycles as sampling time 
// ADC Channel 0 is connmected to PA0 
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); 
// ADC Channel 1 is connmected to PA1 
ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_239_5Cycles); 
// ADC Calibration 
ADC_GetCalibrationFactor(ADC1); 
//DMA config 
DMA_DeInit(DMA1_Channel1); 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&(ConvADC0_ADC1); 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
DMA_InitStructure.DMA_BufferSize = 2; //sizeof(ConvADC0_ADC1) 
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// DMA_Mode_Circular; //DMA_Mode_Normal;// 
DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
//DMA Enable 
DMA_Cmd(DMA1_Channel1, ENABLE); 
// ADC_DMAMode_OneShot: DMA One Shot Mode 
// ADC_DMAMode_Circular: DMA Circular Mode 
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular); 
// Enable ADC_DMA 
ADC_DMACmd(ADC1, ENABLE); 
// Enable the ADC peripheral 
ADC_Cmd(ADC1, ENABLE); 
// Wait the ADRDY flag 
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
// ADC_StartOfConversion(ADC1); 
} 
unsigned char GetADC() { 
unsigned char curr_signalpegel; 
ADC_StartOfConversion(ADC1); 
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}; 
curr_signalpegel = ConvADC0_ADC1[0]; 
return curr_signalpegel; 
}

7 REPLIES 7
jogerh
Associate II
Posted on July 14, 2015 at 22:20

Dear Community,

I investigated the stm32fxyz_dma.c file (xyz equals 0xx for my case) and found there following function:

void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);

Should I use this function to reset the DMA counter to zero before I start a new ADC comversion – cycle after receiving the EOC flag ?

unsigned char GetADC() { 
unsigned char curr_signalpegel; 
ADC_StartOfConversion(ADC1); 
 //

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}; 
 while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET){};
curr_signalpegel = ConvADC0_ADC1[0]; // read a value
 
 DMA_SetCurrDataCounter(DMA1_Channel_1, 0); //?
 DMA_ClearFlag(DMA1_FLAG_TC1);
 return curr_signalpegel; 
}

Posted on July 14, 2015 at 22:30

You really shouldn't be using EOC, when using DMA consider using HT/TC flags.

For simply grinding over the same memory, with circular, continuous conversions, you need do nothing. It will occur repetitively, in the background, with no further interaction.

To change addresses/sizes of DMA, you're likely going to need to Disable/Enable, or reinitialize.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on July 14, 2015 at 22:32

For non-continuous, ping with

ADC_StartOfConversion(ADC1);

and wait on, and clear the DMA TC
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on July 14, 2015 at 22:34

With

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

the DMA will auto-reinitialize after completion. You wait on, and clear, TC. You light the ADC off again with a start-conversion call.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jogerh
Associate II
Posted on July 14, 2015 at 22:36

CLIVE1,

thankyou for responding –  probably you’ve posted while I edited my post. I will try different combinations and reply if I have results.

Posted on July 14, 2015 at 22:36

Please just write new posts, rather than edit and alter the context/ordering of the thread. Thanks.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jogerh
Associate II
Posted on July 15, 2015 at 09:02

Dear Community,

if you want to discontinuously read more than one ADC channel via ADC then one possibility which works without interrupt (e.g. due to security reasons) is by defining the DMA as a circular one and by setting the ADC_DMARequestModeConfig as a one shot configuration as shown in the following code (I hope this works for all reasons).

unsigned char ConvADC0_ADC1[2]; 
void ADC_Config(void) 
{ 
ADC_InitTypeDef ADC_InitStructure; 
GPIO_InitTypeDef GPIO_InitStructure; 
DMA_InitTypeDef DMA_InitStructure; 
//ADC1 de Init 
ADC_DeInit(ADC1); 
//DMA1 Clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE); 
//GPIO Periph Clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); 
//ADC1 Periph clock enable 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
//GPIO Config for ADC 
// Configure ADC Channel0 
// Configure ADC Channel1 
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(GPIOA, &GPIO_InitStructure); 
// Initialize ADC structure 
ADC_StructInit(&ADC_InitStructure); 
// Configure the ADC1 in continuous mode with a resolution equal to 8 // 12 bits 
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; 
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //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); 
// Convert the ADC1 Channel 0 with 5 Cycles as sampling time 
// ADC Channel 0 is connmected to PA0 
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); 
// ADC Channel 1 is connmected to PA1 
ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_239_5Cycles); 
// ADC Calibration 
ADC_GetCalibrationFactor(ADC1); 
//DMA config 
DMA_DeInit(DMA1_Channel1); 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&(ConvADC0_ADC1); 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
DMA_InitStructure.DMA_BufferSize = 2; //sizeof(ConvADC0_ADC1) 
DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular 
DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
//DMA Enable 
DMA_Cmd(DMA1_Channel1, ENABLE); 
// ADC_DMAMode_OneShot: DMA One Shot Mode 
// ADC_DMAMode_Circular: DMA Circular Mode 
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_OneShot); 
// Enable ADC_DMA 
ADC_DMACmd(ADC1, ENABLE); 
// Enable the ADC peripheral 
ADC_Cmd(ADC1, ENABLE); 
// Wait the ADRDY flag 
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
} 
unsigned char GetADC() { 
unsigned char curr_signalpegel; 
ADC_StartOfConversion(ADC1); 
while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET) {}; 
curr_signalpegel = ConvADC0_ADC1[1]; // read one of the values 
DMA_ClearFlag(DMA1_FLAG_TC1); 
return curr_signalpegel; 
}