EFM32外设--DMA之Timer+DMA+DAC

 

在某些场合,例如想用DAC输出一个正弦波形,最简单的想法就是用一个Timer定时器做一个中断,在中断中,赋给DAC一个新的值,并且触发DAC转换。这样做会有一些弊端,例如在复杂的系统中,中断会有很多个,Timer的中断优先级不可能总是最高的。因此,相位上会有问题。另外,如果用中断,会增加整个系统的功耗。因为需要不停的唤醒MCU,来处理中断。而且功耗和Timer的定时周期息息相关。最后,如果想做一个频率较高的中断,则也会增加整个系统的负担。MCU会忙于处理这个timer中断。执行效率就会下降。

鉴于我们的片内有DMA控制器,因此,我们可以借用DMA来实现这个功能。

实现效果:用Timer的1ms定时,来触发DMA发送数据给DAC,让DAC输出一个指定的波形。

硬件准备:使用TG 的STK, 使用DAC0的CH0来输出一个波形。GPIO口对应为PB11

软件准备:

Timer: 使用系统默认14MHz主频,因此1ms定时的TOP值为14000. 做一个1ms的定时。另外,需要使用DMA来将timer溢出标志位清零,因此,timerInit.dmaClrAct = true;

DMA:源地址为RAM中的数据,目标地址为DAC。触发条件为 chnlCfg.select = DMAREQ_TIMER1_UFOF; //Timer1 的溢出中断标志

DAC:默认配置

例程如下:

#include <stdint.h>
#include <stdbool.h>
#include "efm32.h"
#include "efm32_chip.h"
#include "efm32_cmu.h"
#include "efm32_gpio.h"
#include "efm32_dac.h"
#include "efm32_prs.h"
#include "efm32_dma.h"
#include "efm32_timer.h"

#define DMA_CHANNEL_DAC    2
#define SPITXSAMPLES          9

#pragma data_alignment=256
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2];


/* DMA init structure */
DMA_Init_TypeDef dmaInit;
/* DMA callback structure */
DMA_CB_TypeDef cb[DMA_CHAN_COUNT];

unsigned short ucDACBuffer[SPITXSAMPLES] = {0,400,800,1200,1600,2000,2800,3200,3600};


void DAC_setup(void)
{
    /* Use default settings */
    DAC_Init_TypeDef        init        = DAC_INIT_DEFAULT;
    DAC_InitChannel_TypeDef initChannel = DAC_INITCHANNEL_DEFAULT;
   
    /* Enable the DAC clock */
    CMU_ClockEnable(cmuClock_DAC0, true);
   
    /* Calculate the DAC clock prescaler value that will result in a DAC clock
    * close to 500kHz. Second parameter is zero, if the HFPERCLK value is 0, the
    * function will check what the current value actually is. */
    init.prescale = DAC_PrescaleCalc(500000, 0);
   
    /* Set reference voltage to 1.25V */
    init.reference = dacRef2V5;
   
    /* Initialize the DAC and DAC channel. */
    DAC_Init(DAC0, &init);
    DAC_InitChannel(DAC0, &initChannel, 0);
}

void Timer_Setup(void)
{
    CMU_ClockEnable(cmuClock_TIMER1, true);
    /* Select TIMER0 parameters */ 
    TIMER_Init_TypeDef timerInit =
    {
        .enable     = true,
        .debugRun   = true,
        .prescale   = timerPrescale1,
        .clkSel     = timerClkSelHFPerClk,
        .fallAction = timerInputActionNone,
        .riseAction = timerInputActionNone,
        .mode       = timerModeUp,
        .dmaClrAct  = false,
        .quadModeX4 = false,
        .oneShot    = false,
        .sync       = false,
    };
   
    timerInit.dmaClrAct = true;
    /* Enable overflow interrupt */
    //TIMER_IntEnable(TIMER1, TIMER_IF_OF);
   
    /* Enable TIMER0 interrupt vector in NVIC */
    //NVIC_EnableIRQ(TIMER1_IRQn);
   
    /* Set TIMER Top value */
    TIMER_TopSet(TIMER1, 14000);
   
    /* Configure TIMER */
    TIMER_Init(TIMER1, &timerInit);
}

void DACTransferComplete(unsigned int channel, bool primary, void *user)
{
    DMA_ActivateBasic(DMA_CHANNEL_DAC,
                      true,
                      false,
                      NULL,
                      NULL,
                      SPITXSAMPLES - 1);
}

void DMA_Setup(void)
{
    DMA_CfgChannel_TypeDef  chnlCfg;
    DMA_CfgDescr_TypeDef    descrCfg;
   
    /* Setting up call-back function */ 
    cb[DMA_CHANNEL_DAC].cbFunc = DACTransferComplete;
    cb[DMA_CHANNEL_DAC].userPtr = NULL;
   
    /* Setting up channel */
    chnlCfg.highPri = false;
    chnlCfg.enableInt = true;
    chnlCfg.select = DMAREQ_TIMER1_UFOF;
    chnlCfg.cb = &(cb[DMA_CHANNEL_DAC]);
    DMA_CfgChannel(DMA_CHANNEL_DAC, &chnlCfg);
   
    /* Setting up channel descriptor */
    descrCfg.dstInc = dmaDataIncNone;
    descrCfg.srcInc = dmaDataInc2;
    descrCfg.size = dmaDataSize2;
    descrCfg.arbRate = dmaArbitrate1;
    descrCfg.hprot = 0;
    DMA_CfgDescr(DMA_CHANNEL_DAC, true, &descrCfg);
   
    /*Starting transfer. Using Basic since every transfer must be initiated
    by the ADC. */
    DMA_ActivateBasic(DMA_CHANNEL_DAC,
                      true,
                      false,
                      (void *)&(DAC0->CH0DATA),
                      (void *)&ucDACBuffer,
                      SPITXSAMPLES - 1);
}

void DMAInit(void)

    CMU_ClockEnable(cmuClock_DMA, true);
  /* Initializing the DMA */
  dmaInit.hprot = 0;
  dmaInit.controlBlock = dmaControlBlock;
  DMA_Init(&dmaInit);
}

/**************************************************************************//**
 * @brief  Main function
 *****************************************************************************/
int main(void)
{
    /* Chip errata */
    CHIP_Init();
   
    CMU_ClockEnable(cmuClock_HFPER, true);
    CMU_ClockEnable(cmuClock_GPIO, true);
   
    DMAInit();
    DAC_setup();
    /* Enable DAC channel 0, located on pin PB11 */
    DAC_Enable(DAC0, 0, true);
   
    Timer_Setup();
    DMA_Setup();
   
    unsigned short usDACValue = 0;;
    /* Infinite blink loop */
    while (1)
    {
       
    }
}

最终的效果:

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值