Question
Problem with reading ADC channels group using DMA
Posted on September 30, 2013 at 11:35
I am using STM32F407VG.
I've read documentation about ADC and groups and still don't know how to set up properly ADC to sample periodically fixed ADC channels. I've done this by following code but don't know if this is right. I want to use ADC2, sample group of channels 10, 11, 12, 13 and 0 in this order. Samples tranfered using DMA. Currently using TIM2 and update event to trigger sample conversion. DMA config:static
const
DMA_InitTypeDef analog_dma_stream_conf =
{
.DMA_Channel = DMA_Channel_1,
.DMA_PeripheralBaseAddr = (uint32_t)&ANALOG_ADC->DR,
.DMA_Memory0BaseAddr = (uint32_t)analog_dma_buffers[0],
.DMA_BufferSize =
sizeof
(analog_dma_buffers[0]),
.DMA_DIR = DMA_DIR_PeripheralToMemory,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord,
.DMA_Priority = DMA_Priority_High,
.DMA_Mode = DMA_Mode_Normal,
.DMA_FIFOMode = DMA_FIFOMode_Disable,
.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull,
.DMA_MemoryBurst = DMA_MemoryBurst_Single,
.DMA_PeripheralBurst = DMA_PeripheralBurst_Single,
};
DMA_Init(DMA2_Stream3, &analog_dma_stream_conf);
DMA_ITConfig(DMA2_Stream3, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream3, ENABLE);
void
ANALOG_DMA_Stream_IRQHandler(
void
)
{
DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIFx);
struct
analog_sample_vector *next_buf = NULL, *cur_mem;
signed
portBASE_TYPE res = xQueueReceiveFromISR(analog_dma_free_queue, &next_buf, NULL);
if
( res == pdTRUE )
{
cur_mem = (
struct
analog_sample_vector *)ANALOG_DMA_Stream->M0AR;
DMA2_Stream3->M0AR = (uint32_t)next_buf;
DMA2_Stream3->NDTR = ANALOG_BUFFER_SIZE *
sizeof
(
struct
analog_sample_vector);
DMA2_Stream3->CR |= DMA_SxCR_EN;
signed
portBASE_TYPE woken;
res = xQueueSendToBackFromISR(analog_dma_ready_queue, &cur_mem, &woken);
assert
( res == pdTRUE );
analog_thread_ready_waiting |= woken;
portYIELD_FROM_ISR( analog_thread_ready_waiting && xQueueIsQueueEmptyFromISR(analog_dma_free_queue) );
}
else
if
( analog_thread_ready_waiting )
portYIELD();
}
static
const
ADC_InitTypeDef adc2_conf =
{
.ADC_Resolution = ADC_Resolution_12b,
.ADC_ScanConvMode = DISABLE,
.ADC_ContinuousConvMode = DISABLE,
.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising,
.ADC_ExternalTrigConv = ANALOG_ADC_ExternalTrigConv,
.ADC_DataAlign = ADC_DataAlign_Right,
.ADC_NbrOfConversion = 5,
};
RCC_APB2PeriphClockCmd(RCC_APB2ENR_ANALOG_ADCEN, ENABLE);
ADC_Init(ANALOG_ADC, &adc2_conf);
ADC_RegularChannelConfig(ADC2, ADC_Channel_10, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 3, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 4, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC2, ADC_Channel_0, 5, ADC_SampleTime_480Cycles);
ADC_DMACmd(ADC2, ENABLE);
Then the trigger config
TIM_TimeBaseInitTypeDef timer_conf;
timer_conf.TIM_Prescaler = presc ? presc - 1 : 0;
timer_conf.TIM_CounterMode = TIM_CounterMode_Up;
timer_conf.TIM_Period = period - 1;
timer_conf.TIM_ClockDivision = TIM_CKD_DIV1;
timer_conf.TIM_RepetitionCounter = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInit(TIM2, &timer_conf);
TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
TIM_Cmd(TIM2, ENABLE);
The problem is I am getting only one DMA interrupt. It seams that ADC stops requesting DMA transfers, but looked at register it seems all is set ok.
Does anyone have any hints or code snippet that uses ADC channels group periodically sampled and and is using DMA. Maby better datasheet?
#tim #group #dma #adc