AnsweredAssumed Answered

STM32F4 ADC Triple Mode with DMA

Question asked by pantelis on Jun 24, 2015
Latest reply on Jun 24, 2015 by pantelis
Hello everyone!

I have a problem while trying to implement ADC Triple Mode with DMA and I would like your help if possible.

Initially, I wanted to implement it with sequential data transfer (DMA mode 1) and afterwards the final goal is DMA mode 2. The first case worked successfully, however I have a difficult time while implementing the Multi DMA mode 2.

First of all, I have some difficulties in terms of initiallization and secondly I am trying to understand how to get the correct data. The only way I can think of is when every separate DMA transfer is complete, use the interrupt to split the data of the filled variable in 2 separate variables and get my two values (eg ADC1 and ADC2). But on the other hand I am thinking that if that is the case, then it may not be that faster compared to the DMA mode 1. Could you please enlighten me on how to get my data while using dma MODE 2?

Below is the code I wrote for the implementation of the above ( in my application I want to get 3 measurements simultaneously, one from every ADC in pins PC0(ADC1), PC1(ADC2) and PC2(ADC3).

Header file

#include "stm32f4xx_conf.h"

ADC_InitTypeDef       ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef       DMA_InitStructure;
GPIO_InitTypeDef      GPIO_InitStructure;
NVIC_InitTypeDef       NVIC_InitStructure2;

extern volatile uint32_t Measuredvalues[3];

void ADC_Config(void);
void DMA_Config(void);


C File

#include "ADC_DMA.h"

volatile uint32_t Measuredvalues[3];

void ADC_Config(void)
{

  /* Enable ADC1, ADC2, ADC3 and GPIO clocks */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

  /* Configure ADC1 Channel10, ADC2 Channel 11 and ADC3 Channel 12 pins as analog inputs (Correspond to PC0, PC1 and PC2)*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);


  /* ADC Common Init (ADC_CCR register) */
  ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult; // ADC_Mode_Independent for 1 ADC. For ADC123, it will change to ADC_TripleMode_RegSimult!
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2; //ADC_DMAAccessMode_1; Enable it in mode 2 or 3 with multi input
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* ADC1 Init (ADC_CR1 & ADC_CR2 registers)*/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE; // Each ADC Scans one channel so I think that even in triple mode it won't be used
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1; // One signal scanning
  ADC_Init(ADC1, &ADC_InitStructure);
  ADC_Init(ADC2, &ADC_InitStructure);
  ADC_Init(ADC3, &ADC_InitStructure);

  /* ADC1 regular channel10 configuration*/
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
  ADC_Cmd(ADC2, ENABLE);
  ADC_Cmd(ADC3, ENABLE);

}


void DMA_Config(void)
{
      // Enable DMA clocks
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);


      // DMA2 Stream0 channe0 configuration for ADC1
      DMA_InitStructure.DMA_Channel = DMA_Channel_0;  // Represents the channel of DMA2 Used by ADC1(RM0090 Table 43)
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR; // Address of ADC Common Data register &ADC1->DR; &ADC->CDR; RM0090 Table.72
      DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&Measuredvalues; //Measuredvalues or AnlgInput.A
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
      DMA_InitStructure.DMA_BufferSize = 2;
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
      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_FIFOMode = DMA_FIFOMode_Disable;
      DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
      DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
      DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
      DMA_Init(DMA2_Stream0, &DMA_InitStructure);
      DMA_Cmd(DMA2_Stream0, ENABLE);

      /*
      // DMA2 Stream2 channe1 configuration for ADC2
      DMA_InitStructure.DMA_Channel = DMA_Channel_1;
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR; // Address of ADC2 Data register RM0090 Table.72
      DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&AnlgInput.B;
      DMA_Init(DMA2_Stream2, &DMA_InitStructure);
      DMA_Cmd(DMA2_Stream2, ENABLE);

      // DMA2 Stream1 channe2 configuration for ADC3
      DMA_InitStructure.DMA_Channel = DMA_Channel_2;
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC3->DR; // Address of ADC3 Data register RM0090 Table.72
      DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&AnlgInput.C;
      DMA_Init(DMA2_Stream1, &DMA_InitStructure);
      DMA_Cmd(DMA2_Stream1, ENABLE);
      */


      /* Enable DMA request after last transfer (Multi-ADC mode)  */
      ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

      /*
      // Enable DMA request after last transfer (Single-ADC mode)
        ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
        ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
        ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
      */

      // Enable ADC1 DMA since it is the master
      ADC_DMACmd(ADC1, ENABLE);
      /*
      ADC_DMACmd(ADC2, ENABLE);
      ADC_DMACmd(ADC3, ENABLE);
      */

      // Start ADC1 Software Conversions
      ADC_SoftwareStartConv(ADC1);
      ADC_SoftwareStartConv(ADC2);
      ADC_SoftwareStartConv(ADC3);


      //Once transfer is done, generate interrupt
      /*
      NVIC_InitStructure2.NVIC_IRQChannel = DMA2_Stream0_IRQn;
      NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure2.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure2);
      */

}



Thank you in advance!

Outcomes