简体   繁体   English

使用DMA的STM32F3 DAC信号生成

[英]STM32F3 DAC signal generation using DMA

I'm writing a program that is supposed to generate sine wave using DAC on my STM32f3Discovery board. 我正在STM32f3Discovery板上编写一个程序,该程序应该使用DAC生成正弦波。 I have it in several files, listed below. 我有几个文件,在下面列出。

Utilities.h: 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: 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. 因此,从理论上讲,它应该在引脚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. 如果其他人有兴趣,似乎可以驱动DAC_1的唯一合适的DMA通道是DMA2通道3。可以以某种方式将其重新映射到DMA1通道3,但仍在困扰着它。

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: 如果对某人有帮助,请按照以下所有必要步骤操作,以使DAC在STM32f3上正常运行:

  1. Enable clock for timerX (gotta see what timers are available to trigger DAC with TRGO event), DMA, DAC and GPIOA. 启用timerX的时钟(必须查看哪些计时器可用于通过TRGO事件触发DAC),DMA,DAC和GPIOA。 If you wanna use non-default DMA for DAC, enable clock for SYSCFG. 如果要将非默认DMA用于DAC,请为SYSCFG启用时钟。

  2. Set up desired DAC channel. 设置所需的DAC通道。 Note that on STM32f3 Discovery there is only 1 DAC with 2 channels. 请注意,在STM32f3 Discovery上,只有1个具有2个通道的DAC。 DACch1 out is PA4, DACch2 out is PA5. DACch1输出为PA4,DACch2输出为PA5。

  3. Configure selected GPIOA as analog input and init. 将选定的GPIOA配置为模拟输入和初始化。

  4. Configure DAC and init. 配置DAC和初始化。 Remember to enable DMA for DAC. 请记住为DAC启用DMA。

  5. If you wanna change default settings for DMA to use with DAC use SYSCFG_DMAChannelRemapConfig command. 如果要更改与DAC一起使用的DMA的默认设置,请使用SYSCFG_DMAChannelRemapConfig命令。

  6. Configure DMA and init. 配置DMA和初始化。

  7. Configure desired timer and init. 配置所需的计时器和初始化。 Remember to set up TRGO interrupt! 记住要设置TRGO中断!

Below I'm including working code for sine wave generation on DACch1 using non-default DMA. 下面,我包括使用非默认DMA在DACch1上生成正弦波的工作代码。

#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. 首先检查您的MCU是否具有DAC模块。 There might be no DAC peripheral in which case no sine wave will be generated. 可能没有DAC外设,在这种情况下将不会产生正弦波。 you can check this in the data sheet for your specific microcontroller package. 您可以在数据手册中针对您的特定微控制器封装进行检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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