AnsweredAssumed Answered

STM32F405 - triple adc dma fires just once

Question asked by Vinci on Dec 26, 2014
Latest reply on Jan 2, 2015 by Vinci
Hello

I'd like to run all three ADCs of the STM32F405 in regular simultaneous mode and use DMA to load the values to a buffer. I'm sure this problem has occurred before but all the examples I found are using the old libraries which aren't really comparable to the new HAL functions.

So far I got the ADC and the DMA working for one single measurement cycle. If I restart the cycle without resetting or re-initializing the peripherals only the ADC works. The debugger shows me that the ADC_CDR register is getting filled with new values, but for some reason the DMA doesn't copy it to the desired location although a DMA transfer complete interrupt is triggered?

For some other reason I also get ADC overrun errors from time to time but I couldn't reproduce this every time and it seems to occur randomly...


I've added the initialization although I'm pretty sure that's not the problem. I guess I'm using the HAL_ADCEx_MultiModeStart_DMA function wrong? Does anyone have a working example with the new libraries?

Initialization:
void adc_init(void)
{
    ADC_ChannelConfTypeDef sConfig;
    ADC_MultiModeTypeDef multimode;
 
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
     */
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
    hadc1.Init.Resolution = ADC_RESOLUTION12b;
    hadc1.Init.ScanConvMode = DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.NbrOfDiscConversion = 1;
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
    HAL_ADC_Init(&hadc1);
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
     */
    sConfig.Channel = ADC_CHANNEL_10;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
 
    /**Configure the ADC multi-mode
     */
    multimode.Mode = ADC_TRIPLEMODE_REGSIMULT;
    multimode.DMAAccessMode = ADC_DMAACCESSMODE_1;
    multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
    HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);
 
 
 
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
     */
    hadc2.Instance = ADC2;
    hadc2.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
    hadc2.Init.Resolution = ADC_RESOLUTION12b;
    hadc2.Init.ScanConvMode = DISABLE;
    hadc2.Init.ContinuousConvMode = DISABLE;
    hadc2.Init.DiscontinuousConvMode = DISABLE;
    hadc2.Init.NbrOfDiscConversion = 1;
    hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc2.Init.NbrOfConversion = 1;
    hadc2.Init.EOCSelection = EOC_SINGLE_CONV;
    HAL_ADC_Init(&hadc2);
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
     */
    sConfig.Channel = ADC_CHANNEL_11;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
    HAL_ADC_ConfigChannel(&hadc2, &sConfig);
 
    /**Configure the ADC multi-mode
     */
    multimode.Mode = ADC_TRIPLEMODE_REGSIMULT;
    multimode.DMAAccessMode = ADC_DMAACCESSMODE_1;
    multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
    HAL_ADCEx_MultiModeConfigChannel(&hadc2, &multimode);
 
 
 
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
     */
    hadc3.Instance = ADC3;
    hadc3.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
    hadc3.Init.Resolution = ADC_RESOLUTION12b;
    hadc3.Init.ScanConvMode = DISABLE;
    hadc3.Init.ContinuousConvMode = DISABLE;
    hadc3.Init.DiscontinuousConvMode = DISABLE;
    hadc3.Init.NbrOfDiscConversion = 1;
    hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc3.Init.NbrOfConversion = 1;
    hadc3.Init.EOCSelection = EOC_SINGLE_CONV;
    HAL_ADC_Init(&hadc3);
 
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
     */
    sConfig.Channel = ADC_CHANNEL_12;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
    HAL_ADC_ConfigChannel(&hadc3, &sConfig);
 
    /**Configure the ADC multi-mode
     */
    multimode.Mode = ADC_TRIPLEMODE_REGSIMULT;
    multimode.DMAAccessMode = ADC_DMAACCESSMODE_1;
    multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
    HAL_ADCEx_MultiModeConfigChannel(&hadc3, &multimode);
}
 
 
// ***********************************************************************
// @brief   This function handles the base initialization of ADC and DMA.
//          (__weak version found in stm32f4xx_hal_adc.c)
// ***********************************************************************
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    if(hadc->Instance==ADC1)
    {
        /* Peripheral clock enable */
        __ADC1_CLK_ENABLE();
 
        /**ADC1 GPIO Configuration
        PC0   ------> ADC1_IN10
         */
        GPIO_InitStruct.Pin = GPIO_PIN_0;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
        /* Peripheral DMA init*/
 
        hdma_adc1.Instance = DMA2_Stream0;
        hdma_adc1.Init.Channel = DMA_CHANNEL_0;
        hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
        hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        hdma_adc1.Init.Mode = DMA_CIRCULAR;
        hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
        hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        HAL_DMA_Init(&hdma_adc1);
 
        __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);
 
    }
    else if(hadc->Instance==ADC2)
    {
        /* Peripheral clock enable */
        __ADC2_CLK_ENABLE();
 
        /**ADC2 GPIO Configuration
        PC1   ------> ADC2_IN11
         */
        GPIO_InitStruct.Pin = GPIO_PIN_1;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
        /* Peripheral DMA init*/
 
        hdma_adc2.Instance = DMA2_Stream2;
        hdma_adc2.Init.Channel = DMA_CHANNEL_1;
        hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
        hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        hdma_adc2.Init.Mode = DMA_CIRCULAR;
        hdma_adc2.Init.Priority = DMA_PRIORITY_LOW;
        hdma_adc2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        HAL_DMA_Init(&hdma_adc2);
 
        __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc2);
 
    }
    else if(hadc->Instance==ADC3)
    {
        /* Peripheral clock enable */
        __ADC3_CLK_ENABLE();
 
        /**ADC3 GPIO Configuration
        PC2   ------> ADC3_IN12
         */
        GPIO_InitStruct.Pin = GPIO_PIN_2;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
        /* Peripheral DMA init*/
 
        hdma_adc3.Instance = DMA2_Stream1;
        hdma_adc3.Init.Channel = DMA_CHANNEL_2;
        hdma_adc3.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_adc3.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_adc3.Init.MemInc = DMA_MINC_ENABLE;
        hdma_adc3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        hdma_adc3.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        hdma_adc3.Init.Mode = DMA_CIRCULAR;
        hdma_adc3.Init.Priority = DMA_PRIORITY_LOW;
        hdma_adc3.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        HAL_DMA_Init(&hdma_adc3);
 
        __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc3);
    }
 
 
      HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
 
 
// ***********************************************************************
// @brief   This function handles DMA2 stream0 interrupts.
// ***********************************************************************
void DMA2_Stream0_IRQHandler(void)
{
    HAL_DMA_IRQHandler(hadc1.DMA_Handle);
}
 
Main:
uint16_t buffer[3] = {0};
dma_init();
adc_init();
 
while (1)
{
    HAL_ADC_Start(&hadc2);
    HAL_ADC_Start(&hadc3);
    HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)buffer, 3);
    HAL_Delay(100);
}

Outcomes