简体   繁体   中英

STM32F3 DAC signal generation using DMA

I'm writing a program that is supposed to generate sine wave using DAC on my STM32f3Discovery board. I have it in several files, listed below.

Utilities.h:

#ifndef UTILITIES_H
#define UTILITIES_H

/** @brief Configure GPIOE, pin 9 (LED) as output PP
 */
void GPIOE_init( void );

/** @brief Configure Timer 2, event frequency - 100Hz
 */
void Timer_init( void );

/** @brief Configure interrupt handler
 */
void NVIC_config( void );

/** @brief Configure and enable DAC channel 1 on pin PA4,
 *  with TIM2 TRGO as trigger
 */
void DACch1_config( void );

/** @brief Configure DMA to work with DAC
 */
void DMA_config( void );

#endif //UTILITIES_H

Utilities.c:

#include "utilities.h"
#include "stm32f30x.h"

const uint16_t sineWave12bit[32] = {
        2048,2447,2831,3185,3495,3750,3939,4056,
        4095,4056,3939,3750,3495,3185,2831,2447,
        2048,1648,1264,910,600,345,156,39,
        0,39,156,345,600,910,1264,1648 };

//This address is taken from reference manual for stm32f30
//See pages 53 and 439
#define DAC_DHR12RD_ADDRESS 0x40007420

void Timer_init( void ){

    /* Configuring frequency of timer, thus sinus frequency */
    /* Keep in mind, that system clock is set to 80Mhz */
    TIM_TimeBaseInitTypeDef    timer2;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_TimeBaseStructInit( &timer2 );
    timer2.TIM_CounterMode = TIM_CounterMode_Up;
    //Setting prescaler so that timer clock will be only 10000Hz
    timer2.TIM_Prescaler = 8000 - 1;
    //Setting period so Timer will give signal of frequency 100Hz
    timer2.TIM_Period = 100 - 1;
    TIM_TimeBaseInit( TIM2, &timer2 );

    //generate event when counter hits TIM_period value
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

    /* TIM2 enable counter */
    TIM_Cmd(TIM2, ENABLE);
}

void NVIC_config( void ){
    NVIC_InitTypeDef nvic;

    nvic.NVIC_IRQChannel = TIM2_IRQn;
    nvic.NVIC_IRQChannelPreemptionPriority = 0;
    nvic.NVIC_IRQChannelSubPriority = 0;
    nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &nvic );
}


void GPIOE_init( void ){
    /* GPIOE initialization */
    GPIO_InitTypeDef        leds;

    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOE, ENABLE );

    leds.GPIO_Pin = GPIO_Pin_9;
    leds.GPIO_Mode = GPIO_Mode_OUT;
    leds.GPIO_OType = GPIO_OType_PP;
    leds.GPIO_Speed = GPIO_Speed_50MHz;
    leds.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOE, &leds);
}

void DACch1_config( void ){
      /*******THERE IS ONLY ONE DAC ON STM32F30!!!!!!!!!!!!!!!!!!******************/
      DAC_InitTypeDef   DACch1;
      GPIO_InitTypeDef  DACch1_out;

      /* Enable GPIOA Periph clock */
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

      /* Configure PA04 as analog  */
      DACch1_out.GPIO_Pin =  GPIO_Pin_4;
      DACch1_out.GPIO_Mode = GPIO_Mode_AN;
      DACch1_out.GPIO_OType = GPIO_OType_PP;
      DACch1_out.GPIO_PuPd = GPIO_PuPd_NOPULL;
      DACch1_out.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &DACch1_out);

      /* Enable DAC clock */
      RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE );

      /* Init the DAC_Init structure */
      DAC_StructInit(&DACch1);

      /* Configure DAC */
      DACch1.DAC_Trigger = DAC_Trigger_T2_TRGO;
      DACch1.DAC_WaveGeneration = DAC_WaveGeneration_None;
      DACch1.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits2_0;
      DACch1.DAC_OutputBuffer = DAC_OutputBuffer_Disable;

      /* DAC channel 1 configuration*/
      DAC_Init( DAC_Channel_1, &DACch1 );

      /* Enable DAC channel 1       */
      DAC_Cmd( DAC_Channel_1, ENABLE);
}


void DMA_config( void ){
    DMA_InitTypeDef mem2DAC;

    /* Enable clock for DMA1 */
    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );

    /* Reset DMA1 channel 1 register values to default */
    DMA_DeInit(DMA1_Channel1);

    //Specify destination address
    mem2DAC.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS;
    //Specify source address - LUT for sine
    mem2DAC.DMA_MemoryBaseAddr = (uint32_t) &sineWave12bit;
    //Set Peripheral as destination
    mem2DAC.DMA_DIR = DMA_DIR_PeripheralDST;
    mem2DAC.DMA_BufferSize = 32;
    mem2DAC.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    mem2DAC.DMA_MemoryInc = DMA_MemoryInc_Enable;
    mem2DAC.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    mem2DAC.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    mem2DAC.DMA_Mode = DMA_Mode_Circular;
    mem2DAC.DMA_Priority = DMA_Priority_High;
    mem2DAC.DMA_M2M = DMA_M2M_Disable;

    DMA_Init( DMA1_Channel1, &mem2DAC );

    /* Enable DMA1 Channel1 */
    DMA_Cmd( DMA1_Channel1, ENABLE );

    /* Enable DMA fo DAC channel 1*/
    DAC_DMACmd( DAC_Channel_1, ENABLE );

}

main.c:

/**
  ******************************************************************************
  * @file    main.c
  * @author  Ac6
  * @version V1.0
  * @date    01-December-2013
  * @brief   Default main function.
  ******************************************************************************
*/


#include "stm32f30x.h"
#include "utilities.h"

int main(void)
{
    DMA_config();

    DACch1_config();

    Timer_init();

    while(1){

    }
}

So in theory it should generate sine wave on pin A.04. However when I look at the voltage on this pin using osciloscope, it shows nothing (ground potential).

Does anyone has any idea what could be wrong?

Alright, I fixed it. If anyone else is interested, it seems like the only suitable DMA channel that can drive DAC_1 is DMA2 channel 3. It can be somehow remapped to DMA1 channel 3, im still strugling with it.

EDIT:

Got everything working. If it is of any help to someone, here are all necessary steps in order to get DAC woring on STM32f3:

  1. Enable clock for timerX (gotta see what timers are available to trigger DAC with TRGO event), DMA, DAC and GPIOA. If you wanna use non-default DMA for DAC, enable clock for SYSCFG.

  2. Set up desired DAC channel. Note that on STM32f3 Discovery there is only 1 DAC with 2 channels. DACch1 out is PA4, DACch2 out is PA5.

  3. Configure selected GPIOA as analog input and init.

  4. Configure DAC and init. Remember to enable DMA for DAC.

  5. If you wanna change default settings for DMA to use with DAC use SYSCFG_DMAChannelRemapConfig command.

  6. Configure DMA and init.

  7. Configure desired timer and init. Remember to set up TRGO interrupt!

Below I'm including working code for sine wave generation on DACch1 using non-default DMA.

#include "utilities.h"
#include "stm32f30x.h"

const uint16_t sineWave12bit[64] = {
        2048,2248,2447,2642,2831,3013,3185,3346,
        3495,3630,3750,3853,3939,4007,4056,4085,
        4095,4085,4056,4007,3939,3853,3750,3630,
        3495,3346,3185,3013,2831,2642,2447,2248,
        2048,1847,1648,1453,1264,1082,910,749,
        600,465,345,242,156,88,39,10,
        0,10,39,88,156,242,345,465,
        600,749,910,1082,1264,1453,1648,1847 };

//This address is taken from reference manual for stm32f30
//See pages 53 and 439
#define DAC_DHR12R1_ADDRESS 0x40007408

void Timer_init( void ){

    /* Configuring frequency of timer, thus sinus frequency */
    /* Keep in mind, that system clock is set to 80Mhz */
    TIM_TimeBaseInitTypeDef    timer2;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_TimeBaseStructInit( &timer2 );
    timer2.TIM_CounterMode = TIM_CounterMode_Up;
    //Setting prescaler so that timer clock will be only 10000Hz
    timer2.TIM_Prescaler = 8000 - 1;
    //Setting period so Timer will give signal of frequency 1000Hz
    timer2.TIM_Period = 10 - 1;
    TIM_TimeBaseInit( TIM2, &timer2 );

    //generate event when counter hits TIM_period value
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

    /* TIM2 enable counter */
    TIM_Cmd(TIM2, ENABLE);
}

void NVIC_config( void ){
    NVIC_InitTypeDef nvic;

    nvic.NVIC_IRQChannel = TIM2_IRQn;
    nvic.NVIC_IRQChannelPreemptionPriority = 0;
    nvic.NVIC_IRQChannelSubPriority = 0;
    nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &nvic );
}


void GPIOE_init( void ){
    /* GPIOE initialization */
    GPIO_InitTypeDef        leds;

    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOE, ENABLE );

    leds.GPIO_Pin = GPIO_Pin_9;
    leds.GPIO_Mode = GPIO_Mode_OUT;
    leds.GPIO_OType = GPIO_OType_PP;
    leds.GPIO_Speed = GPIO_Speed_50MHz;
    leds.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOE, &leds);
}

void DACch1_config( void ){
      /*******THERE IS ONLY ONE DAC ON STM32F30!!!!!!!!!!!!!!!!!!******************/
      DAC_InitTypeDef   DACch1;
      GPIO_InitTypeDef  DACch1_out;

      /* Enable GPIOA Periph clock */
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

      /* Configure PA04 as analog  */
      DACch1_out.GPIO_Pin =  GPIO_Pin_4;
      DACch1_out.GPIO_Mode = GPIO_Mode_AN;
      DACch1_out.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOA, &DACch1_out);

      /* Enable DAC clock */
      RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE );

      /* Init the DAC_Init structure */
      DAC_StructInit(&DACch1);

      /* Reset DAC configuration */
      DAC_DeInit();

      /* Configure DAC */
      DACch1.DAC_Trigger = DAC_Trigger_T2_TRGO;
      DACch1.DAC_WaveGeneration = DAC_WaveGeneration_None;
      DACch1.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits2_0;
      DACch1.DAC_OutputBuffer = DAC_OutputBuffer_Enable;

      /* DAC channel 1 configuration*/
      DAC_Init( DAC_Channel_1, &DACch1 );

      /* Enable DAC channel 1       */
      DAC_Cmd( DAC_Channel_1, ENABLE);
}


void DMA_config( void ){
    DMA_InitTypeDef mem2DAC;

    /* Enable clock for SYSCFG in order to change DMA for DAC from
     * DMA2 channel3 to DMA1 channel 3 (default is DMA2 channel 3) */
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_SYSCFG, ENABLE );

    /* Use DMA1 channel 3 for DAC1 */
    SYSCFG_DMAChannelRemapConfig( SYSCFG_DMARemap_TIM6DAC1, ENABLE );

    /* Enable clock for DMA1 */
    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );

    /* Reset DMA1 channel 1 register values to default */
    DMA_DeInit( DMA1_Channel3 );

    mem2DAC.DMA_PeripheralBaseAddr = DAC_DHR12R1_ADDRESS;
    mem2DAC.DMA_MemoryBaseAddr = (uint32_t)&sineWave12bit;
    mem2DAC.DMA_DIR = DMA_DIR_PeripheralDST;
    mem2DAC.DMA_BufferSize = 64;
    mem2DAC.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    mem2DAC.DMA_MemoryInc = DMA_MemoryInc_Enable;
    mem2DAC.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    mem2DAC.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    mem2DAC.DMA_Mode = DMA_Mode_Circular;
    mem2DAC.DMA_Priority = DMA_Priority_High;
    mem2DAC.DMA_M2M = DMA_M2M_Disable;

    DMA_Init( DMA1_Channel3, &mem2DAC );

    /* Enable DMA1 Channel1 */
    DMA_Cmd( DMA1_Channel3, ENABLE );

    /* Enable DMA fo DAC channel 1*/
    DAC_DMACmd( DAC_Channel_1, ENABLE );

}

I encountered a similar problem. firstly check if your MCU has a DAC block. There might be no DAC peripheral in which case no sine wave will be generated. you can check this in the data sheet for your specific microcontroller package.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM