2014-02-14 06:33 AM
Hi,
I'm working with stm32F0 and I want read ADC multichannel. My question is: is it possible without DMA?Thanks2014-02-14 07:11 AM
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?2014-02-14 07:20 AM
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?
2014-02-14 07:58 AM
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.2014-02-14 08:26 AM
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
2014-02-14 09:09 AM
is there any error?
Several. You'd want a buffer size of 3 with your modelvoid 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 readRegularConvData_Tab
[0][1][2], and on TCRegularConvData_Tab
[3][4][5]2014-02-14 09:27 AM
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);
// ...
2014-02-16 11:13 PM
Thanks Clive1!!!!