AnsweredAssumed Answered

program to read two ADCs using DMA and driving one DACs using DMA

Question asked by das.sanjib on Jan 18, 2014
Latest reply on Jan 23, 2014 by das.sanjib
I am trying to    read two ADCs using DMA and driving one DACs using DMA
But I am not able to get the DAC output can anybody say me what mistake I am doing



// STM32 ADC IQ Sample @ 200 KHz (PC.0, PC.1) STM32F4 Discovery

// Assumptions per system_stm32f4xx.c CPU @ 128 MHz, APB2 @ 64  MHz max is 84 (/2), APB1 @ 32 MHz max is 42 (/4)


/**

/* Includes ------------------------------------------------------------------*/
#include "unistd.h"
#include "stm32f4xx.h"
#include "stm32f4_discovery.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx.h"
#include <misc.h>
#include "stm32f4xx_adc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_usart.h"

//#include <stdio.h>

/* Private typedef -----------------------------------------------------------*/
GPIO_InitTypeDef  GPIO_InitStructure;
/* Private define ------------------------------------------------------------*/
#define ADC_PERIP_ADD    (uint32_t)0x40012308
#define DAC_OP_PERIP_ADD    (uint32_t)&DAC->DOR1;
#define BUFFERSIZE         1024
/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
uint32_t ADCDualConvertedValues[BUFFERSIZE];
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  RCC_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    RCC Configuration for peripherals
  */
void RCC_Configuration(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);        //Enable clock for GPIO A (ADC Pins and DAC Pins)
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);        //Enable clock for DMA1 (DAC DMA)
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);        //Enable clock for DMA2 (ADC DMA)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //Enable clock for TIM2 (used for ADC Trigger)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);        //Enable clock for TIM6 (used for DAC Trigger)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);        //Enable clock for ADC1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);        //Enable clock for ADC2
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);            //Enable clock for DAC

}

/**
  * @brief  GPIO_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    GPIO Configuration
  */
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3|GPIO_Pin_4;       //Enable the PA02, PA03 (for ADC) and PA04(for DAC)
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                            //Set as Analog mode
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}


/**
  * @brief  TIMER2_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    TIMER2 Configuration For ADC
  * Issue
  * 16-Jan-2014 Sanjib -  Solved the Problem of ADC_trigger timer interrupt by setting the PSC register and
  * ARR    register to 2 - 1 and 200 - 1 for 6.25 us . as register are index starting from 0 . So we have to
  * set the register with the required value by decrementing it with 1.
  *
  */
void TIMER2_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 200 - 1;                            //Timer clock for 6.25us
    TIM_TimeBaseStructure.TIM_Prescaler = 2 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);                  // ADC_ExternalTrigConv_T2_TRGO
    TIM_Cmd(TIM2, ENABLE);                                                // TIM2 enable counter
}


/**
  * @brief  TIMER6_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    TIMER6 Configuration For DAC
  */
void TIMER6_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 200 - 1;                         //Timer clock for 6.25us
    TIM_TimeBaseStructure.TIM_Prescaler = 2 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
    TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);               // DAC_ExternalTrigConv_T2_TRGO

}


/**
  * @brief  NVIC_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    NVIC Configuration for ADC DMA Stream0 So that we can initiate DMA transfer
  */
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;                                 //Enable the DMA Stream IRQ Channel
    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);
}


/**
  * @brief  DMA_ADC_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    DMA Configuration for ADC
  */
void DMA_ADC_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                // Enable channel 0 for DMA
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDualConvertedValues;    //Assigning the memory Base address
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC_PERIP_ADD;                     //Assigning the peripheral Address// CDR_ADDRESS; Packed ADC1, ADC2
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                        //DMA_transfer_dir-Peripheral to memory
    DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //Peripheral address pointer is fixed
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //Memory increment as per as memory size
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;    //DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;            //DMA_MemoryDataSize_Halfword
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                //Circular mode
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                            //Priority_high
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;                        //To enable the use of the FIFO threshold level, the direct mode must be disabled
    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);                                    //Update the registers
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);                    //Enable DMA Stream Half / Transfer Complete interrupt
    DMA_Cmd(DMA2_Stream0, ENABLE);                                                //DMA2_Stream0 enable

}


/**
  * @brief  ADC_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    ADC Configuration
  */
void ADC_Configuration(void)
{
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef ADC_InitStructure;


    ADC_CommonInitStructure.ADC_Mode =  ADC_DualMode_RegSimult;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;                 //2 half-words one by one, 1 then 2
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;     //really required this?
    ADC_CommonInit(&ADC_CommonInitStructure);

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                            //12 bit resolution
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;                                     //ScanConvMode = DISABLE means Multi channel disabled
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                             //ContinuousConvMode = DISABLE means Triggered conversion mode
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 1;                                        //expecting 1 conversion for both ADC 1 and 2
    ADC_Init(ADC1, &ADC_InitStructure);                                                //updating the register for ADC1
    ADC_Init(ADC2, &ADC_InitStructure);                                             //updating the register for ADC2


    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_15Cycles);      //ADC1 regular channel2 configuration

    ADC_RegularChannelConfig(ADC2, ADC_Channel_3, 1, ADC_SampleTime_15Cycles);         //ADC2 regular channel3 configuration


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

    ADC_Cmd(ADC1, ENABLE);                                                            //Enable ADC1

    ADC_Cmd(ADC2, ENABLE);                                                            //Enable ADC2

}


/**
  * @brief  DMA_DAC_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    DMA Configuration for DAC to fed the data in ADC DMA buffer as soon as it triggers the half buffer completion
  */
void DMA_DAC_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_Channel = DMA_Channel_7;                                //Enable channel 7 for DMA
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDualConvertedValues;    //Assigning the memory Base address
    DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_OP_PERIP_ADD;            //Assigning the peripheral Address// CDR_ADDRESS; DAC CH1
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                        //DMA_transfer_dir-Memory to Peripheral
    DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //Peripheral address pointer is fixed
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //Memory increment as per as memory size
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;    //DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;                //DMA_MemoryDataSize_Halfword
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                //Circular mode
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                            //Priority_high
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;                        //To enable the use of the FIFO threshold level, the direct mode must be disabled
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA1_Stream5, &DMA_InitStructure);                                    //Update the registers

    DMA_Cmd(DMA1_Stream5, ENABLE);                                                //DMA2_Stream5 enable

}


/**
  * @brief  DAC_Configuration
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    DAC Configuration for channel 1
  */
void DAC_Configuration(void)
{

    DAC_InitTypeDef DAC_InitStructure;
    DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;                    //DAC channel1 trigger enable
    DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
    DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;            //DAC_Output_Buffer_enable

    DAC_Init(DAC_Channel_1, &DAC_InitStructure);
    DAC_Cmd(DAC_Channel_1, ENABLE);                                            // DAC control reg,  channels  1 ON
    DAC->CR |= 0x00001000;                                                     //DMA mode enabled for DAC channel 1


}


/**
  * @brief  DMA2_Stream0_Handler
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    Interrupt hanndler for half transfer as well as full transfer
  */
void DMA2_Stream0_IRQHandler(void) // Called at 1 KHz for 200 KHz sample rate, LED Toggles at 500 Hz
{

    int i;
    TIM_Cmd(TIM2, ENABLE);                                                // TIM2 enable counter
    STM_EVAL_LEDOn(LED3);


  }


/**
  * @brief  Main program
  * @param  None
  * @retval None
  * Author  Sanjib
  * Desc    program to read two ADCs using DMA and driving one DACs using DMA
  */
int main(void)
{

    RCC_Configuration();

    GPIO_Configuration();

    NVIC_Configuration();

    TIMER2_Configuration();

    TIMER6_Configuration();

    DMA_ADC_Configuration();

    ADC_Configuration();

    DAC_Configuration();

    DMA_DAC_Configuration();
    STM_EVAL_LEDInit(LED3);


#if 0


     // GPIO_Configuration();

       DAC_configure();
        NVIC_Configuration();

        TIM2_Configuration();


        DMA_Configuration();

        ADC_Configuration();
#endif



        while(1); // Don't want to exit
}

      /**************************************************************************************/

      #ifdef  USE_FULL_ASSERT

      /**
        * @brief  Reports the name of the source file and the source line number
        *   where the assert_param error has occurred.
        * @param  file: pointer to the source file name
        * @param  line: assert_param error line source number
        * @retval None
        */
      void assert_failed(uint8_t* file, uint32_t line)
      {
        /* User can add his own implementation to report the file name and line number,
           ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

        /* Infinite loop */
        while (1)
        {
        }
      }
      #endif

Outcomes