Skip to main content
marcogrossi89
Associate III
November 27, 2014
Question

DAC waveform generation with DMA not working

  • November 27, 2014
  • 9 replies
  • 1384 views
Posted on November 27, 2014 at 15:45

I am using the STM32L Discovery Board (STML152RB chip on board). The IDE is Emblocks. I was trying to generate a sawtooth wave signal using DAC and DMA but it does not work. I was able to make the same program without DMA (by triggering an interrupt at regular time with a timer and updating the DAC value inside the interrup handler) but with DMA it does not work. Below is the code I use. Anyone can help to fix it?

#include ''stm32l1xx_conf.h''

#include <stm32l1xx.h>

#include <stm32l1xx_rcc.h>

#include <stm32l1xx_gpio.h>

#include <stm32l1xx_tim.h>

#include <stm32l1xx_dac.h>

#include <stm32l1xx_dma.h>

#include <misc.h>

#include <math.h>

#define WAVE_FREQ 5000

#define WAVE_POINTS 100

#define TIMER_PERIOD 9

uint16_t wave_array[100];

uint8_t j;

float pi_greco = 3.14159;

int timervalue;

void GPIO_initialize(void)

{

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitTypeDef gpioStructure;

    gpioStructure.GPIO_Pin = GPIO_Pin_5;

    gpioStructure.GPIO_Mode = GPIO_Mode_AIN;

    GPIO_Init(GPIOA, &gpioStructure);

}

void DAC_initialize(void)

{

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

RCC_APB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_DeInit(DMA1_Channel1);

DMA_InitTypeDef DMA_Structure;

    DMA_Structure.DMA_PeripheralBaseAddr = (uint32_t) &DAC->DHR12R2;

    DMA_Structure.DMA_MemoryBaseAddr = (uint32_t) &wave_array;

    DMA_Structure.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_Structure.DMA_BufferSize = WAVE_POINTS;

    DMA_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_Structure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

    DMA_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

    DMA_Structure.DMA_Mode = DMA_Mode_Circular;

    DMA_Structure.DMA_Priority = DMA_Priority_High;

    DMA_Structure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel1, &DMA_Structure);

    DAC_InitTypeDef DAC_Structure;

DAC_Structure.DAC_Trigger = DAC_Trigger_T6_TRGO;

DAC_Structure.DAC_WaveGeneration = DAC_WaveGeneration_None;

DAC_Structure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;

DAC_Init(DAC_Channel_2, &DAC_Structure);

    DMA_Cmd(DMA1_Channel1, ENABLE);

    DAC_DMACmd(DAC_Channel_2, ENABLE);

DAC_Cmd(DAC_Channel_2, ENABLE);

}

void TIM6_initialize(void)

{

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

TIM_TimeBaseInitTypeDef timerInitStructure;

timerInitStructure.TIM_Prescaler = 319;

timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

timerInitStructure.TIM_Period = TIMER_PERIOD;

timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseInit(TIM6, &timerInitStructure);

TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);

TIM_Cmd(TIM6, ENABLE);

}

int main(void)

{

    for(j=0; j<100; j++)

        {

        wave_array[j] = (uint16_t)(500 + 20*j);

        }

    GPIO_initialize();

    TIM6_initialize();

    DAC_initialize();

  while(1)

  {

  }

}

    This topic has been closed for replies.

    9 replies

    stm322399
    Senior
    November 27, 2014
    Posted on November 27, 2014 at 15:58

    According RM0038, DAC_channel2 trigs DMA1_channel3. I do not catch why DAC_ch2 is associated with TIM7, but if I were you I will use TIM7 instead of TIM6.

    Or you can use the DAC_Channel1/TIM6/DMA1_Channel2 combination as well.

    marcogrossi89
    Associate III
    November 27, 2014
    Posted on November 27, 2014 at 16:10

    Changed DMA_Channel1 with DMA_Channel3 and TIM6 with TIM7 but again it is not working

    stm322399
    Senior
    November 27, 2014
    Posted on November 27, 2014 at 16:22

    Does it still work with TIM7 and no DMA ?

    marcogrossi89
    Associate III
    November 27, 2014
    Posted on November 27, 2014 at 18:15

    Yes. It works also with TIM7. However with the no DMA version there is also another difference: the event that triggers the DAC update is TIM_IT_Update with no DMA and 

    TIM_TRGOSource_Update with DMA (since this was used in a code I found on the web).

    Tesla DeLorean
    Guru
    November 27, 2014
    Posted on November 27, 2014 at 18:16

    #include ''stm32l1xx_conf.h''
    #include <
    stm32l1xx.h
    >
    #include <
    stm32l1xx_rcc.h
    >
    #include <
    stm32l1xx_gpio.h
    >
    #include <
    stm32l1xx_tim.h
    >
    #include <
    stm32l1xx_dac.h
    >
    #include <
    stm32l1xx_dma.h
    >
    #include <
    misc.h
    >
    #include <
    math.h
    >
    #define WAVE_FREQ 5000
    #define WAVE_POINTS 100
    #define TIMER_PERIOD 10
    uint16_t wave_array[100];
    uint8_t j;
    float pi_greco = 3.14159;
    int timervalue;
    void GPIO_initialize(void)
    {
    GPIO_InitTypeDef gpioStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    gpioStructure.GPIO_Pin = GPIO_Pin_5;
    gpioStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &gpioStructure);
    }
    void DAC_initialize(void)
    {
    DMA_InitTypeDef DMA_Structure;
    DAC_InitTypeDef DAC_Structure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA1_Channel3); // DAC2 -> DMA1 Ch3
    DMA_Structure.DMA_PeripheralBaseAddr = (uint32_t) &DAC->DHR12R2;
    DMA_Structure.DMA_MemoryBaseAddr = (uint32_t) &wave_array[0];
    DMA_Structure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_Structure.DMA_BufferSize = WAVE_POINTS;
    DMA_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_Structure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_Structure.DMA_Mode = DMA_Mode_Circular;
    DMA_Structure.DMA_Priority = DMA_Priority_High;
    DMA_Structure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel3, &DMA_Structure);
    DAC_Structure.DAC_Trigger = DAC_Trigger_T6_TRGO;
    DAC_Structure.DAC_WaveGeneration = DAC_WaveGeneration_None;
    DAC_Structure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
    DAC_Init(DAC_Channel_2, &DAC_Structure);
    DMA_Cmd(DMA1_Channel3, ENABLE);
    DAC_DMACmd(DAC_Channel_2, ENABLE);
    DAC_Cmd(DAC_Channel_2, ENABLE);
    }
    void TIM6_initialize(void)
    {
    TIM_TimeBaseInitTypeDef timerInitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
    timerInitStructure.TIM_Prescaler = 320-1;// 32MHz -> 100KHz
    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    timerInitStructure.TIM_Period = TIMER_PERIOD - 1; // DIV10, 100KHz -> 10KHz
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM6, &timerInitStructure);
    TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
    TIM_Cmd(TIM6, ENABLE);
    }
    int main(void)
    {
    for(j=0; j<100; j++)
    {
    wave_array[j] = (uint16_t)(500 + 20*j);
    }
    GPIO_initialize();
    TIM6_initialize();
    DAC_initialize();
    while(1)
    {
    }
    }

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stm322399
    Senior
    November 27, 2014
    Posted on November 27, 2014 at 18:41

    RCC_APB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    of course this is the best candidate to explain why it does not work.

    marcogrossi89
    Associate III
    November 28, 2014
    Posted on November 28, 2014 at 10:17

    Used the code suggested by clive1 and also fixed the RCC statement

    RCC_AHB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    with

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    but the code still does not work.

    Tesla DeLorean
    Guru
    November 28, 2014
    Posted on November 28, 2014 at 13:46

    Yes did this all blind, I don't have any boards/scopes with me right now.

    Could confirm timer is firing using TIM interrupt and/or toggling LED or pin.
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    marcogrossi89
    Associate III
    November 28, 2014
    Posted on November 28, 2014 at 17:36

    Now it seems to work. I have found some code on the web and replicated it with minor changes. Following is the working code. Moved to TIM2 but I do not think this is the problem. Maybe DAC definition should be made just after GPIO definition and both defined after DMA definition. Not sure.

    #include ''stm32l1xx_conf.h''

    #include <stm32l1xx.h>

    #include <stm32l1xx_rcc.h>

    #include <stm32l1xx_gpio.h>

    #include <stm32l1xx_tim.h>

    #include <stm32l1xx_dac.h>

    #include <stm32l1xx_dma.h>

    #include <misc.h>

    #include <math.h>

    #define WAVE_FREQ 5000

    #define WAVE_POINTS 100

    #define TIMER_PERIOD 10

    #define DAC_DHR12RD_Address      0x40007420

    uint16_t wave_array[100];

    uint16_t j;

    float pi_greco = 3.14159;

    int timervalue;

    void DAC_initialize(void)

    {

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

        GPIO_InitTypeDef gpioStructure;

        gpioStructure.GPIO_Pin = GPIO_Pin_5;

        gpioStructure.GPIO_Mode = GPIO_Mode_AIN;

        GPIO_Init(GPIOA, &gpioStructure);

        DAC_InitTypeDef DAC_Structure;

    DAC_Structure.DAC_Trigger = DAC_Trigger_T2_TRGO;

    DAC_Structure.DAC_WaveGeneration = DAC_WaveGeneration_None;

    DAC_Structure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;

    DAC_Init(DAC_Channel_2, &DAC_Structure);

    DAC_Cmd(DAC_Channel_2, ENABLE);

        DAC_DMACmd(DAC_Channel_2, ENABLE);

    }

    void DMA_initialize(void)

    {

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel3);

    DMA_InitTypeDef DMA_Structure;

        DMA_Structure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address;

        DMA_Structure.DMA_MemoryBaseAddr = (uint32_t) &wave_array;

        DMA_Structure.DMA_DIR = DMA_DIR_PeripheralDST;

        DMA_Structure.DMA_BufferSize = WAVE_POINTS;

        DMA_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

        DMA_Structure.DMA_MemoryInc = DMA_MemoryInc_Enable;

        DMA_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

        DMA_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

        DMA_Structure.DMA_Mode = DMA_Mode_Circular;

        DMA_Structure.DMA_Priority = DMA_Priority_High;

        DMA_Structure.DMA_M2M = DMA_M2M_Disable;

        DMA_Init(DMA1_Channel3, &DMA_Structure);

        DMA_Cmd(DMA1_Channel3, ENABLE);

    }

    void TIM2_initialize(void)

    {

       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

        TIM_TimeBaseInitTypeDef timerInitStructure;

    timerInitStructure.TIM_Prescaler = 320-1;

    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    timerInitStructure.TIM_Period = TIMER_PERIOD-1;

    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInit(TIM2, &timerInitStructure);

    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

    TIM_Cmd(TIM2, ENABLE);

    }

    int main(void)

    {

        for(j=0; j<100; j++)

            {

            wave_array[j] = (uint16_t)(2000 + 1500*sin((2*pi_greco*j)/100));

            // wave_array[j] = (uint16_t)(500+20*j);

            }

        DMA_initialize();

        DAC_initialize();

        TIM2_initialize();

      while(1)

      {

      }

    }