AnsweredAssumed Answered

Triple ADC mode with DMA [STM32F4 discovery]

Question asked by ronan on Feb 20, 2012
Latest reply on May 19, 2014 by kamba.hugues
Hi everybody,

I want use the ADC converter with the DMA controler. I must do the conversion of 9 analog voltages. The converter configured in regular simultaneous mode (Triple ADC mode).

I want trigger an interrupt when 9 analog tensions are converted and logged in memory.

Here is the code :

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>

/* Private macro */

/* Private define ------------------------------------------------------------*/
#define ADC_CDR_ADDRESS    ((uint32_t)0x40012308)

/* Private variables ---------------------------------------------------------*/
__IO uint16_t ADCTripleConvertedValue[9];


int main(void)
{
    uint16_t i;

    // Initialisation Hardware
    HwInit();

    for (i=0;i<9;i++)
    {
        ADCTripleConvertedValue[i]=i;
    }

    /* Infinite loop */

    while (1)
    {
        /* Analog to digital converter */
        ADC_SoftwareStartConv(ADC1);                    // Start ADC
        LED3On();
        DelayMS(500);

        LED3Off();
        DelayMS(500);
    }
}


/**************************************************************************
  * @descr  Initialise les differents peripheriques
  * @param  None
  * @retval None
  *************************************************************************/
void HwInit( void )
{
    CLKInit();                    // Initialise la clock

    LED3Init();                    // Initialise la lED3
    LED4Init();                    // Initialise la lED4
    LED5Init();                    // Initialise la lED5
    LED6Init();                    // Initialise la lED6

    ADCInit();
    UART3Init();

    NVIC_Config();

}

/**************************************************************************
  * @descr  Configure l'horloge du systeme avec Horloge externe de 8 MHz
  *             PLL_M    8            PLL_N    336
  *             PLL_Q    7             PLL_P    2
  *             SYSCLK    168 MHz
  *
  * @param  None
  * @retval None
  *************************************************************************/
void CLKInit( void)
{
    SystemInit();                                // Setup Microcontroller System

    RCC->CR = RCC->CR | RCC_CR_HSEON;            // HSE Oscillator ON

    RCC->PLLCFGR =     RCC->PLLCFGR |
                    RCC_PLLCFGR_PLLQ_0 |        // PLLQ = 7 (0111)
                    RCC_PLLCFGR_PLLQ_1 |
                    RCC_PLLCFGR_PLLQ_2 |
                    RCC_PLLCFGR_PLLSRC_HSE |    // HSE oscillator selected as PLL clock entry
                    RCC_PLLCFGR_PLLN_8 |        // PLLN = 336 (101010000)
                    RCC_PLLCFGR_PLLN_6 |
                    RCC_PLLCFGR_PLLN_4 |
                    RCC_PLLCFGR_PLLM_3;            // PLLM = 8 (001000)

    RCC->CFGR = RCC->CFGR | RCC_CFGR_SW_PLL;    // PLL selected as system clock

    SystemCoreClockUpdate( );                    // Update SystemCoreClock variable 168 MHz

}

/**************************************************************************
  * @descr  Initialise le convertisseur analogique numerique
  * @param  None
  * @retval None
  *************************************************************************/
void ADCInit(void)
{
      GPIO_InitTypeDef      GPIO_AdcInit;
      ADC_InitTypeDef         ADC1_InitStructure;
      ADC_InitTypeDef         ADC2_InitStructure;
      ADC_InitTypeDef         ADC3_InitStructure;
      ADC_CommonInitTypeDef ADC_CommonInitStructure;

      /* Deinitializes the ADC peripheral registers */
      ADC_DeInit();

      /* Enable the GPIOC Clock & ADC1 Periph Clock */
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3, ENABLE);

      /* DMA2 Stream0 channel0 configuration **************************************/
      DMA_Config();

      /* Configure the     PA0 pin (ADC123_IN12)
       *                 PA3 pin (ADC123_IN3)
       *                 PA4 pin (ADC12_IN4)
       *                 PA5 pin (ADC12_IN5)
       *                 PA6 pin (ADC12_IN6) */
      GPIO_AdcInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
      GPIO_AdcInit.GPIO_Mode = GPIO_Mode_AN;
      GPIO_AdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOA, &GPIO_AdcInit);

      /* Configure the     PB0 pin (ADC12_IN8)
       *                 PB1 pin (ADC12_IN9) */
      GPIO_AdcInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
      GPIO_AdcInit.GPIO_Mode = GPIO_Mode_AN;
      GPIO_AdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOB, &GPIO_AdcInit);

      /* Configure the     PC0 pin (ADC123_IN10)
       *                 PC2 pin (ADC123_IN12) */
      GPIO_AdcInit.GPIO_Pin = GPIO_Pin_0  |  GPIO_Pin_2;
      GPIO_AdcInit.GPIO_Mode = GPIO_Mode_AN;
      GPIO_AdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOC, &GPIO_AdcInit);

      /* ADC Common configuration -- ADC_CCR Register */
      ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult ;
      ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
      ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1  ;
      ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
      ADC_CommonInit(&ADC_CommonInitStructure);


      /* ADC1 regular channel 6 configuration -- ADC_CR1, ADC_CR2, ADC_SQR1 Register */
      ADC1_InitStructure.ADC_Resolution = ADC_Resolution_12b;
      ADC1_InitStructure.ADC_ScanConvMode = DISABLE;
      ADC1_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC1_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      ADC1_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC1_InitStructure.ADC_NbrOfConversion = 3;
      ADC_Init(ADC1, &ADC1_InitStructure);

      /* ADC1 regular channel6 configuration -- ADCx->SMPR1,SMPR2 et ADCx->SQR1,SQR2,SQR3  */
      ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_3Cycles);
      ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_3Cycles);
      ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 3, ADC_SampleTime_3Cycles);


      /* ADC2 regular channel 12 configuration -- ADC_CR1, ADC_CR2, ADC_SQR1 Register */
      ADC2_InitStructure.ADC_Resolution = ADC_Resolution_12b;
      ADC2_InitStructure.ADC_ScanConvMode = DISABLE;
      ADC2_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC2_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      ADC2_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC2_InitStructure.ADC_NbrOfConversion = 3;
      ADC_Init(ADC2, &ADC2_InitStructure);

      /* ADC2 regular channel12 configuration -- ADCx->SMPR1,SMPR2 et ADCx->SQR1,SQR2,SQR3  */
      ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);
      ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 2, ADC_SampleTime_3Cycles);
      ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 3, ADC_SampleTime_3Cycles);


      /* ADC3 regular channel 0 configuration -- ADC_CR1, ADC_CR2, ADC_SQR1 Register */
      ADC3_InitStructure.ADC_Resolution = ADC_Resolution_12b;
      ADC3_InitStructure.ADC_ScanConvMode = DISABLE;
      ADC3_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC3_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
      ADC3_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC3_InitStructure.ADC_NbrOfConversion = 3;
      ADC_Init(ADC3, &ADC3_InitStructure);

      /* ADC3 regular channel12 configuration -- ADCx->SMPR1,SMPR2 et ADCx->SQR1,SQR2,SQR3  */
      ADC_RegularChannelConfig(ADC3, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);
      ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 2, ADC_SampleTime_3Cycles);
      ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 3, ADC_SampleTime_3Cycles);

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

      /* Enable ADC1 -- ADC_CR2_ADON */
      ADC_Cmd(ADC1, ENABLE);

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

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

      /* Enable DMA2 Stream0 Transfer complete interrupt */
      DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);

      /* Enable ADC1 DMA since ADC1 is the Master*/
      ADC_DMACmd(ADC1, ENABLE);
}


/**************************************************************************
  * @descr  DMA configuration
  * @param  None
  * @retval None
  *************************************************************************/
void DMA_Config(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValue;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 9;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  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_Enable;
  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);

  /* DMA2_Stream0 enable */
  DMA_Cmd(DMA2_Stream0, ENABLE);
}

uint16_t DMA_GetADC(uint16_t Number)
{
    return ADCTripleConvertedValue[Number];
}

/**************************************************************************
  * @descr  Initialise UART3 - RX:PD9 et TX:PD8
  * @param  None
  * @retval None
  *************************************************************************/
void UART3Init(void)
{
    USART_InitTypeDef UART3_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Enable USART3 clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    /* Connect PD8 and PD9 pins to AF */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);

    /* Configure LED USART3 Tx (PD8) as input floating */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init( GPIOD, &GPIO_InitStructure );

    /* Configure USART3 Rx (PD9) as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_Init( GPIOD, &GPIO_InitStructure );

    /* Initialise Structure UART3 */
    UART3_InitStructure.USART_BaudRate = 9600;
    UART3_InitStructure.USART_WordLength = USART_WordLength_8b;
    UART3_InitStructure.USART_StopBits = USART_StopBits_1;
    UART3_InitStructure.USART_Parity = USART_Parity_No;
    UART3_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    UART3_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    /* Initialise UART3 */
    USART_Init(USART3,&UART3_InitStructure);

    /* Enable the interrupt Rx UART3 */
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);

    /* Enable the UART3 */
    USART_Cmd( USART3, ENABLE );

}

/**************************************************************************
  * @descr  Envoie d'un caractere via l'UARTx
  * @param  USARTx    definie l'uart à utiliser (1,2,3,4,5,6)
  * @param    Data    caractere à transferer
  * @retval None
  *************************************************************************/
void USART_SendChar(USART_TypeDef* USARTx, unsigned char Data)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));

  /* Transmit Data */
  USARTx->DR = (Data & (uint16_t)0x01FF);
}

/**************************************************************************
  * @descr  Envoie d'une chaine de caracteres via l'UARTx
  * @param  USARTx    definie l'uart à utiliser (1,2,3,4,5,6)
  * @param    s        chaine de caracteres à transferer
  * @retval None
  *************************************************************************/
void USART_SendString(USART_TypeDef* USARTx, char *s)
{
    /* Check the parameters */
    assert_param(IS_USART_ALL_PERIPH(USARTx));

    while(*s)
    {
        while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
        USART_SendData(USARTx, *s++);
    }
}


/**************************************************************************
  * @descr  Initialise la "Nested Vectored Interrupt Controller"
  * @param  None
  * @retval None
  *************************************************************************/
void NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the USART3 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable the DMA2 Stream0 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

The problem is there is only an interrupt after three conversion instead of one conversion ?

Thanks for your help !

Outcomes