AnsweredAssumed Answered

Triple mode ADC with new HAL

Question asked by Twoism on Dec 2, 2014
Latest reply on Dec 16, 2014 by cole.chris
Hello,
I'm trying to set the ADC(s) of the stm32f407 in triple mode, using DMA for data transfers. Based on the the only available example in the cube package and some old code, written using the stdpheriph, I wrote the following code but unfortunately it doesn't work. It never calls the DMA Interrupt service routine and the value in the ADC->CDR register stay stuck to the first conversion. Here's the code:

void HAL_ADC_MspInit(ADC_HandleTypeDef* adc_handler)
{
    GPIO_InitTypeDef gpio_init_struct;
    static DMA_HandleTypeDef dma_adc_handler;
  
    /*
    Pins timer alternate function mapping:
    -----------------------
    Pin        ADC     Channel
    -----------------------
    PA01    ADC1    CH1
    PA02    ADC2    CH2
    PA03    ADC3    CH3
    */
  
    // Enable DMA, ADC 1,2,3 and related GPIO ports clock
    __DMA2_CLK_ENABLE();
  
    __ADC1_CLK_ENABLE();
    __ADC2_CLK_ENABLE();
    __ADC3_CLK_ENABLE();
  
    __GPIOA_CLK_ENABLE();
  
    // ADCs GPIO pin configuration
    gpio_init_struct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
    gpio_init_struct.Mode = GPIO_MODE_ANALOG;
    gpio_init_struct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &gpio_init_struct);
  
    // ADC1 master, ADC 2,3 slaves
    // DMA2 Stream0 channel0 (physically mapped to ADC1) configuration
    dma_adc_handler.Instance = DMA2_Stream0;
    dma_adc_handler.Init.Channel = DMA_CHANNEL_0;
    dma_adc_handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    dma_adc_handler.Init.PeriphInc = DMA_PINC_DISABLE;
    dma_adc_handler.Init.MemInc = DMA_MINC_ENABLE;
    dma_adc_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    dma_adc_handler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    dma_adc_handler.Init.Mode = DMA_CIRCULAR;
    dma_adc_handler.Init.Priority = DMA_PRIORITY_HIGH;
    dma_adc_handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    dma_adc_handler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    dma_adc_handler.Init.MemBurst = DMA_MBURST_SINGLE;
    dma_adc_handler.Init.PeriphBurst = DMA_PBURST_SINGLE;
  
    HAL_DMA_Init(&dma_adc_handler);
  
    // Associate the initialized DMA handle to the the ADC handle
    __HAL_LINKDMA(adc_handler, DMA_Handle, dma_adc_handler);
  
    // NVIC configuration for DMA transfer complete interrupt
    HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
  
//---------------------------------------------------------------------------------------------------------
  
void Befm_Sense::init()
{
    // ADC(s) configuration
    adc1_handle.Instance = ADC1;
    adc1_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;    //0 [1] -> max ADC clock
    adc1_handle.Init.Resolution = ADC_RESOLUTION12b;
    adc1_handle.Init.ScanConvMode = DISABLE;
    adc1_handle.Init.ContinuousConvMode = ENABLE;
    adc1_handle.Init.DiscontinuousConvMode = DISABLE;
    adc1_handle.Init.NbrOfDiscConversion = 0;
    adc1_handle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONVEDGE_NONE;
    adc1_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
//    adc1_handle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
//    adc1_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
    adc1_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    adc1_handle.Init.NbrOfConversion = 1;
    adc1_handle.Init.DMAContinuousRequests = ENABLE;
    adc1_handle.Init.EOCSelection = EOC_SINGLE_CONV;
  
    adc2_handle.Instance = ADC2;
    adc2_handle.Init = adc1_handle.Init;
  
    adc3_handle.Instance = ADC3;
    adc3_handle.Init = adc1_handle.Init;
  
  
    if (HAL_ADC_Init(&adc1_handle) != HAL_OK) {
        info::error();
    }
  
    if (HAL_ADC_Init(&adc2_handle) != HAL_OK) {
        info::error();
    }
  
    if (HAL_ADC_Init(&adc3_handle) != HAL_OK) {
        info::error();
    }
  
    // Configure ADC1 regular channel 1
    adc_config_struct.Channel = ADC_CHANNEL_1;
    adc_config_struct.Rank = 1;
    adc_config_struct.SamplingTime = ADC_SAMPLETIME_15CYCLES;
    adc_config_struct.Offset = 0;
    if(HAL_ADC_ConfigChannel(&adc1_handle, &adc_config_struct) != HAL_OK) {
        info::error();
    }
  
    // Configure ADC2 regular channel 2
    adc_config_struct.Channel = ADC_CHANNEL_2;
    if(HAL_ADC_ConfigChannel(&adc2_handle, &adc_config_struct) != HAL_OK) {
        info::error();
    }
  
    // Configure ADC3 regular channel 3
    adc_config_struct.Channel = ADC_CHANNEL_3;
    if(HAL_ADC_ConfigChannel(&adc3_handle, &adc_config_struct) != HAL_OK) {
        info::error();
    }
  
    // Configure ADC(s) in triple-mode simultaneous
    adc_multimode_struct.Mode = ADC_TRIPLEMODE_REGSIMULT;
    adc_multimode_struct.DMAAccessMode = ADC_DMAACCESSMODE_1;
    adc_multimode_struct.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
    if (HAL_ADCEx_MultiModeConfigChannel(&adc1_handle, &adc_multimode_struct) != HAL_OK) {
        info::error();
    }
  
    if (HAL_ADCEx_MultiModeConfigChannel(&adc2_handle, &adc_multimode_struct) != HAL_OK) {
        info::error();
    }
  
    if (HAL_ADCEx_MultiModeConfigChannel(&adc3_handle, &adc_multimode_struct) != HAL_OK) {
        info::error();
    }
  
    // Start ADC
    // Enables ADC DMA request after last transfer (Multi-ADC mode) and enables ADC peripheral
    // Only master ADC (ADC1)
    if (HAL_ADCEx_MultiModeStart_DMA(&adc1_handle, (uint32_t *)&phases_v, 3) != HAL_OK) {
        info::error();
    }
}
  
//---------------------------------------------------------------------------------------------------------
  
// DMA (ADC) interrupt handler
void DMA2_Stream0_IRQHandler(void)
{
    HAL_DMA_IRQHandler(adc1_handle.DMA_Handle);
}
  
  
void ADC_IRQHandler(void)
{
    HAL_ADC_IRQHandler(&adc1_handle);
}

I've done many tests but I can't figure out why it doesn't work or if it's correct due to the lack of example code.

Outcomes