cancel
Showing results for 
Search instead for 
Did you mean: 

ADC without DMA

mosine
Associate II
Posted on February 14, 2014 at 15:33

Hi,

I'm working with stm32F0 and I want read ADC multichannel. My question is: is it possible without DMA?

Thanks
7 REPLIES 7
Posted on February 14, 2014 at 16:11

I'm working with stm32F0 and I want read ADC multichannel. My question is: is it possible without DMA?

Given the simplicity of using DMA in this context, I've never asked myself the question.

My question to you would be can you service the EOC interrupt quickly enough?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mosine
Associate II
Posted on February 14, 2014 at 16:20

Thanks for reply clive1. My situation is: I have sampled the value read on 3 different ADC channels. Every 5 msec (timer interrupt), I have read ADC channel1 then ADC channel2 and then channel3. Is DMA only solution? 

Posted on February 14, 2014 at 16:58

Is DMA only solution?

Probably not, then again your approach is to climb over the mountain rather than drive through the tunnel.

You're not approaching the problem properly.

What you'd typically do on STM32 architectures is set up a timer to trigger the ADC start-of-conversion to a group of 3 channels every 5 ms in hardware, the DMA would have a circular buffer of 3 x 2 samples, and an interrupt on the DMA HT and TC conditions. Then every 5 ms you'd get a single interrupt that's the equivalent to THREE-CHANNEL-END-OF-CONVERSION and the measurements would be instantly ready to use.

You're certainly welcome to experiment with your approach of initiating the ADC and spinning on the results.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mosine
Associate II
Posted on February 14, 2014 at 17:26

Thanks clive!!! After your reply (I have seen manual and examples...), I wrote this code:

DMA_InitTypeDef DMA_InitStructure;
/* Configure ADC PA3 PA4 as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure ADC PC0 as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* ADC1 DeInit */
ADC_DeInit(ADC1);
/* ADC1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* DMA1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
/* DMA1 Channel1 Config */
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&RegularConvData_Tab[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 5;
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_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* DMA1 Channel1 enable */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);
/* Configure the ADC1 in continous mode with a resolution 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; // 1 .. 5 !
ADC_Init(ADC1, &ADC_InitStructure);
/* Convert the ADC1 Channel 3,4,10 with 5 Cycles as sampling time */ 
ADC_ChannelConfig(ADC1, ADC_Channel_3 , ADC_SampleTime_239_5Cycles); 
ADC_ChannelConfig(ADC1, ADC_Channel_4 , ADC_SampleTime_239_5Cycles); 
ADC_ChannelConfig(ADC1, ADC_Channel_10 , ADC_SampleTime_239_5Cycles); 
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Wait the ADCEN flag */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
/* ADC DMA request in circular mode */
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
/* Enable ADC_DMA */
ADC_DMACmd(ADC1, ENABLE);
/* ADC1 regular Software Start Conv */
ADC_StartOfConversion(ADC1);

In TIM15 interrupt (5msec), I read the value ofRegularConvData_Tab:

void TIM15_IRQHandler(void)
{
if (TIM_GetITStatus(TIM15, TIM_IT_Update) != RESET)
{
while((DMA_GetFlagStatus(DMA1_FLAG_TC1)) == RESET ); 
ADC1ConvertedValueMA = RegularConvData_Tab[0];
ADC1ConvertedValuePH = RegularConvData_Tab[1]; 
ADC1ConvertedValueV = RegularConvData_Tab[2];
/* Clear DMA TC flag */
DMA_ClearFlag(DMA1_FLAG_TC1);
TIM_ClearITPendingBit(TIM15, TIM_IT_Update);
}

is there any error? Thanks
Posted on February 14, 2014 at 18:09

is there any error?

Several. You'd want a buffer size of 3 with your model

void TIM15_IRQHandler(void)
{
if (TIM_GetITStatus(TIM15, TIM_IT_Update) != RESET) // Qualify
{
TIM_ClearITPendingBit(TIM15, TIM_IT_Update); // Clear Early
// Do other work
}
}

What I've suggested is:

DMA_InitStructure.DMA_BufferSize = 3 * 2; // THREE Samples, TWO Halves

Don't use the TIM IRQ, Trigger the ADC from the TIM, don't use continuous mode, interrupt on the DMA HT/TC events. On HT you can read

RegularConvData_Tab

[0][1][2], and on TC

RegularConvData_Tab

[3][4][5]
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 14, 2014 at 18:27

Triggering an ADC from TIM directly

// In TIM15 initialization
TIM_SelectOutputTrigger(TIM15, TIM_TRGOSource_Update); // Source for ADC_ExternalTrigConv_T15_TRGO
// ...
/* Configure the ADC1 in continous mode with a resolution equal to 12 bits */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Triggered when required
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T15_TRGO; // Start-of-Conversion
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward; // 1 .. 3
ADC_Init(ADC1, &ADC_InitStructure);
/* Convert the ADC1 Channel 3,4,10 with 5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_3 , ADC_SampleTime_239_5Cycles); 
ADC_ChannelConfig(ADC1, ADC_Channel_4 , ADC_SampleTime_239_5Cycles); 
ADC_ChannelConfig(ADC1, ADC_Channel_10 , ADC_SampleTime_239_5Cycles); 
// ...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
mosine
Associate II
Posted on February 17, 2014 at 08:13

Thanks Clive1!!!!