2015-07-14 08:00 AM
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;
}
2015-07-14 01:20 PM
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;
}
2015-07-14 01:30 PM
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.2015-07-14 01:32 PM
For non-continuous, ping with
ADC_StartOfConversion(ADC1);
and wait on, and clear the DMA TC
2015-07-14 01:34 PM
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.
2015-07-14 01:36 PM
CLIVE1,
thankyou for responding – probably you’ve posted while I edited my post. I will try different combinations and reply if I have results.
2015-07-14 01:36 PM
Please just write new posts, rather than edit and alter the context/ordering of the thread. Thanks.
2015-07-15 12:02 AM
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;
}