cancel
Showing results for 
Search instead for 
Did you mean: 

STM32f407 - ADC regular-simultaneous mode

lukasz
Associate
Posted on February 14, 2014 at 00:05

Hello all

I am trying to configure stm32f407 MCU to work in ADC regular-simultaneous dual mode, but with no luck so far. I hope that some of you could point where the bug is. Generally, the idea is to gather two streams of samples and store them in uint32_t array of size ADC1_CONV_CNT. Samples of two streams should be moved to array by DMA reading from ADC1's DR register. When DMA fills whole array it should rise an interrupt which has to count average for both streams and store them in avg1, avg2 variables. Then array filling process should start from the beginning and so on.

Here is the code I use:

/* system configuration */

 

void adc_init_dual_regsimultaneous(void)

 

{

 

    /* init RCC */

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

 

 

    /* init GPIO */

 

    GPIO_InitTypeDef GPIO_InitStructure;

 

    GPIO_StructInit(&GPIO_InitStructure);

 

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_3;

 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;

 

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

 

    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;

 

    GPIO_Init(GPIOC, &GPIO_InitStructure);

 

 

    /* init NVIC */

 

    NVIC_InitTypeDef NVIC_InitStruct;

 

 

    NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream0_IRQn;

 

    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;

 

    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;

 

    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

 

 

    NVIC_Init(&NVIC_InitStruct);

 

 

    /* init DMA */

 

    DMA_InitTypeDef DMA_InitStruct;

 

    DMA_DeInit(DMA2_Stream0);

 

 

    DMA_InitStruct.DMA_Channel = DMA_Channel_0;

 

    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;

 

    DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)ADC1_vals;

 

    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; //PeripheralSRC;

 

    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;

 

    DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

 

    DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;

 

    DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

 

    DMA_InitStruct.DMA_BufferSize = ADC1_CONV_CNT;

 

    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

 

    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;

 

    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

 

    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;

 

    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;

 

    DMA_InitStruct.DMA_Priority = DMA_Priority_High;

 

    //DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

 

 

    DMA_Init(DMA2_Stream0, &DMA_InitStruct);

 

    DMA2_Stream0->CR |= DMA_SxCR_TCIE;

 

 

    /* init ADC common */

 

    ADC_CommonInitTypeDef ADC_CommonInitStructure;

 

 

    ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;

 

    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;

 

    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;

 

    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;

 

 

    ADC_CommonInit(&ADC_CommonInitStructure);

 

    ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

 

 

    /* init ADC1 */

 

    ADC_InitTypeDef ADC_InitStructure;

 

    ADC_StructInit(&ADC_InitStructure);

 

 

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

 

    ADC_InitStructure.ADC_ScanConvMode = DISABLE;

 

    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

 

    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

 

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;

 

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

 

    ADC_InitStructure.ADC_NbrOfConversion = 1;

 

 

    ADC_Init(ADC1, &ADC_InitStructure);

 

    ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 1, ADC_SampleTime_480Cycles);

 

    //commented ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

 

 

    /* init ADC2 */

 

    ADC_StructInit(&ADC_InitStructure);

 

 

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

 

    ADC_InitStructure.ADC_ScanConvMode = DISABLE;

 

    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

 

    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

 

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;

 

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

 

    ADC_InitStructure.ADC_NbrOfConversion = 1;

 

 

    ADC_Init(ADC2, &ADC_InitStructure);

 

    ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 1, ADC_SampleTime_480Cycles);

 

 

    /* enabling */

 

    DMA_Cmd(DMA2_Stream0, ENABLE);

 

    ADC_DMACmd(ADC1, ENABLE);

 

 

    ADC_SoftwareStartConv(ADC1);

 

}

 

 

/* interrupt code */

 

void DMA2_Stream0_IRQHandler(void)

 

{

 

    avg1 = test_avg1(1);

 

    avg2 = test_avg1(0);

 

    DMA2->LIFCR = DMA_LISR_TCIF0;

 

}

 

 

/* function which counts average */

 

uint16_t test_avg1(int inc)

 

{

 

    uint32_t sum = 0;

 

 

    uint16_t* array = (uint16_t*)ADC1_vals;

 

    int i;

 

 

    for (i = 0; i < ADC1_CONV_CNT; i++)

 

        sum += array[2*i + inc];

 

 

    return sum / ADC1_CONV_CNT;

 

}

 

What I can see when running above configuration is that interrupt is risen only once and avg1 is updated with correct average, but avg2 is updated by value 0. It's looks like that all half-words are equal to 0 for this stream. No more interrupts is risen. When I comment out this line in configuration:

ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

and uncomment following line:

ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

then interrupt in risen in periodic manner and it updates avg1 properly every time it is executed, but avg2 is still 0.

I will be grateful for any help and suggestion.

3 REPLIES 3
Posted on February 14, 2014 at 00:35

It wouldn't be the ADC1->DR that needs reading, but the common data register for ADC1/ADC2

Clearing the DMA interrupt before leaving is not advisable, you should do this on entry after qualifying the source.

Pretty sure I've previously posted Dual examples.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
lukasz
Associate
Posted on February 15, 2014 at 16:48

Thank you for help!

Regarding DMA suggestion - you mean that I should clear the flag at the beginning of IRQ handler, not at the end, right?