打印
[N32G45x]

求一个DMA双DAC生产两个不同频率的配置实例

[复制链接]
376|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hisungao|  楼主 | 2023-3-8 11:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    如题,将DAC1和DAC2的触发源分别设置成两个定时器和不同时长,使用右对齐DAC_DR12CH1和DAC_DR12CH2,使用DAM方式时只能用一个DAC时才能输出正确频率的正弦波,同时使用两个DAC频率就比计算的低了约20%;
    按手册中的10.4.1中不使用波形发生器独立触发中的描述,似乎只需要选择不同触发源就能实现不同频率输出,但我在使用中将触发源改成两个定时器触发,使用DAC_DR12DCH,输出波形频率比实际计算的也是低了约20%,同时波形好像是DAC1
和DAC叠加在一起并不是正弦波,看DMA,TIM,DAC寄存器的内容和正常波形时寄存器的设置是内容是相同的,就是不知道哪里搞错了。
    求一个用DAM方式同时将两个DAC输出不同频率正弦波的配置例子学习参考,谢谢。

使用特权

评论回复
沙发
hisungao|  楼主 | 2023-3-10 10:09 | 只看该作者
参考例子改了,注释掉TIM_TrgoInit里的TIM2或者TIM4,只使用PA4能得到正确的56.25K或者只使用PA5也能得到正确的102.27K正弦波出来,但是只要将同时使用TIM2和TIM4让DAC1和DAC2同时输出正弦波,那么PA4还是正确的56.25K波,而PA5就只有80K多点跳动,而不是102.27K,求问帮忙指点指点下面改的是哪里不正确搞成这样的错误结果?
另外还有个问题是输出电压峰峰值不是3.3V,官方例子出来的电压是约1.6V,我这里输出频率不一样电压峰峰值也会变,大概是2.7V,这又是为什么?麻烦麻烦各位能看看指点指点,多谢多谢。
#include "n32g45x.h"

/** @addtogroup DAC_DualModeDMA_SineWave
* @{
*/

//#define DAC_DHR12RD_Address 0x40007420
#define DAC_DR12CH1_Address 0x40007408
#define DAC_DR12CH2_Address 0x40007414

/* Init Structure definition */
DAC_InitType DAC_InitStructure;
uint32_t Idx = 0;

const uint16_t Sine12bit[32] = {2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056, 3939,
                                3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909,  599,  344,
                                155,  38,   0,    38,   155,  344,  599,  909,  1263, 1647};

uint32_t DualSine12bit[32];

void RCC_Configuration(void);
void GPIO_Configuration(void);
void TIM_TrgoInit(void);
void DAC_SineWaveInit(void);
void DMA_Config(void);

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
*/
int main(void)
{

    GPIO_Configuration();
    TIM_TrgoInit();
    DAC_SineWaveInit();

    /* Fill Sine32bit table */
//    for (Idx = 0; Idx < 32; Idx++)
//    {
//        DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx]);
//    }
    /* DMA Config */
    DMA_Config();

                TIM_Enable(TIM2, ENABLE);
                TIM_Enable(TIM4, ENABLE);
    while (1)
    {
    }
}

/**
* @brief  Configures the different system clocks.
*/
void RCC_Configuration(void)
{
    /* DAC Periph clock enable */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_DAC, ENABLE);
}

/**
* @brief  Configures the different GPIO ports.
*/
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;

    /* GPIOA Periph clock enable */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    GPIO_InitStructure.Pin       = GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
/**
* @brief  TIM4 Init.
*/
void TIM_TrgoInit(void)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;

    /* TIM4 Periph clock enable */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2  , ENABLE); // RCC_APB2_PERIPH_TIM8
                RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM4  , ENABLE);
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
                TIM_TimeBaseStructure.Period           =39;
    TIM_TimeBaseStructure.Prescaler = 0x0;
    TIM_TimeBaseStructure.ClkDiv    = 0x0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;
                TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);       
       
                TIM_TimeBaseStructure.Period                =21;
    TIM_TimeBaseStructure.Prescaler = 0x0;
    TIM_TimeBaseStructure.ClkDiv    = 0x0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;
                TIM_InitTimeBase(TIM4, &TIM_TimeBaseStructure);

                TIM_SelectOutputTrig(TIM2, TIM_TRGO_SRC_UPDATE);       
                TIM_SelectOutputTrig(TIM4, TIM_TRGO_SRC_UPDATE);
}
/**
* @brief  DAC SineWave Config.
*/
void DAC_SineWaveInit(void)
{
    /* DAC Periph clock enable */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_DAC, ENABLE);

                DAC_InitStructure.Trigger                        = DAC_TRG_T2_TRGO;
    DAC_InitStructure.WaveGen      = DAC_WAVEGEN_NONE;
    DAC_InitStructure.BufferOutput = DAC_BUFFOUTPUT_DISABLE;
                DAC_Init(DAC_CHANNEL_1, &DAC_InitStructure);
       
                DAC_InitStructure.Trigger                        = DAC_TRG_T4_TRGO;
    DAC_InitStructure.WaveGen      = DAC_WAVEGEN_NONE;
    DAC_InitStructure.BufferOutput = DAC_BUFFOUTPUT_DISABLE;
                DAC_Init(DAC_CHANNEL_2, &DAC_InitStructure);

                DAC_Enable(DAC_CHANNEL_1, ENABLE);
                DAC_Enable(DAC_CHANNEL_2, ENABLE);

                DAC_DmaEnable(DAC_CHANNEL_1, ENABLE);
                DAC_DmaEnable(DAC_CHANNEL_2, ENABLE);
       
}
/**
* @brief  DMA Config.
*/
void DMA_Config(void)
{
    DMA_InitType DMA_InitStructure;

    /* DMA2 clock enable */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA2, ENABLE);

//                DMA_DeInit(DMA2_CH3);
                DMA_InitStructure.PeriphAddr                = DAC_DR12CH1_Address;
                DMA_InitStructure.MemAddr                                = (uint32_t)&Sine12bit;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = 32;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_HalfWord ;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
                DMA_Init(DMA2_CH3, &DMA_InitStructure);
                DMA_EnableChannel(DMA2_CH3, ENABLE);

//                DMA_DeInit(DMA2_CH4);
                DMA_InitStructure.PeriphAddr                =DAC_DR12CH2_Address;
                DMA_InitStructure.MemAddr                                = (uint32_t)&Sine12bit;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = 32;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_HalfWord ;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
                DMA_Init(DMA2_CH4, &DMA_InitStructure);

                DMA_EnableChannel(DMA2_CH4, ENABLE);
               
}


使用特权

评论回复
板凳
hisungao|  楼主 | 2023-3-13 22:40 | 只看该作者
我在51黑上下了个ST使用DMA+TIM+DAC生成1K和1.2K双频正弦波的例程对比了下,好像我上面生成的配置没什么问题,应该是可以生成正确的两个不同频率的正弦波的,这几天卡这里,不知道是自己哪里漏掉了啥造成生成的频率和实际的对不上,还是说这个N32G45X用来生成是有点别扭?下面是51黑上的例子代码,完整工程见附件,已用STM32F103VBT6的板子验证过程序正常生成波形正确。麻烦哪位有N32G45板子的兄弟能不能验证下生成两个不同频正弦波的配置是否正确,如配置有误还请能指点一二,实在想知道是自己哪里搞错了还是我买的这块板有问题还是哪里的问题。还有个奇怪的是生成的频率不同输出电压峰峰值也不同,0~4095的打点对应不了0~3.3V,先多谢多谢。 51黑论坛_输出两路不同频率正弦波.rar (4.61 MB)
#include "sign.h"
u16 SineWave1_Value[256];
u16 SineWave2_Value[256];
/********正弦波输出表***********/
//cycle        :波形表的位数        (0~256)
//Um                :输出电压的峰值(0~1.5)
/*******************************/
void SineWave1_Data( u16 cycle ,u16 *D,float Um)
{
    u16 i;
    for( i=0;i<cycle;i++)
    {
        D[i]=(u16)((Um*sin(( 1.0*i/(cycle-1))*2*PI)+Um)*4095/3.3);
    }
}

void SineWave2_Data( u16 cycle ,u16 *D,float Um)
{
    u16 i;
    for( i=0;i<cycle;i++)
    {
        D[i]=(u16)((Um*sin(( 1.0*i/(cycle-1))*2*PI)+Um)*4095/3.3);
    }
}

/****************初始化引脚******************/
void SineWave_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开时钟
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       //推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出速率
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4|GPIO_Pin_5 ; //选择引脚
    GPIO_SetBits(GPIOA,GPIO_Pin_4)  ;   //拉高输出
          GPIO_SetBits(GPIOA,GPIO_Pin_5)  ;   //拉高输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);      //初始化
}

/******************DAC初始化ˉ*************************/
void SineWave_DAC_Config( void)
{
        DAC_InitTypeDef DAC_InitStructure;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//初始化DAC的时钟
        DAC_StructInit(&DAC_InitStructure);
        DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//指定DAC1的触发定时器TIM2
        DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//无波形产生
        DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //不是能DAC输出缓冲
        DAC_Init(DAC_Channel_1, &DAC_InitStructure);//初始化DAC channel1
        DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;//指定DAC2的触发定时器TIM6
        DAC_Init(DAC_Channel_2, &DAC_InitStructure);//初始化DAC channel2
        DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC channel1
        DAC_Cmd(DAC_Channel_2, ENABLE); //使能DAC channel2
        DAC_DMACmd(DAC_Channel_1, ENABLE); //使能DAC Channel1的DMA
        DAC_DMACmd(DAC_Channel_2, ENABLE); //使能DAC Channel2的DMA

       
}



/*********定时器初始化************/
void SineWave_TIM_Config(u32 Wave1_Fre,u32 Wave2_Fre)
{
   TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM6, ENABLE);//开时钟
   TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
   TIM_TimeBaseStructure.TIM_Period = Wave1_Fre; //正弦波1频率设置
   TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //没有预分频
   TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //时钟不分频
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//增计数
   TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
   TIM_TimeBaseStructure.TIM_Period = Wave2_Fre; //正弦波2频率设置
   TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
   TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//更新TIM2输出触发
   TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);//更新TIM6输出触发       

}


/*********DMA配置***********/
void SineWave_DMA_Config(void)
{     
        DMA_InitTypeDef DMA_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//初始化DMA2的时钟
        DMA_DeInit(DMA2_Channel3); //将DMA配置成默认值
        DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;//指定DMA2通道3的目标地址为DAC1_DHR12R1
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SineWave1_Value;//指定DMA的源地址为数组Sine12bit
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为数据传输的目的地
        DMA_InitStructure.DMA_BufferSize = 256;//DMA缓冲区大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设机地址存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度为半字
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存数据宽度为半字
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环缓存模式,数据传输数为0时,自动恢复配置初值
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//非常高优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//通道未被设置成内存到内存模式,与循环模式相对
        DMA_Init(DMA2_Channel3, &DMA_InitStructure);//初始化DMA
        DMA_DeInit(DMA2_Channel4);
        DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R2;//指定DMA2通道3的目标地址为DAC2_DHR12R2
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SineWave2_Value;//指定DMA的源地址为数组Sine12bit
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为数据传输的目的地
        DMA_InitStructure.DMA_BufferSize = 256;//DMA缓冲区大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设机地址存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度为半字
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存数据宽度为半字
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环缓存模式,数据传输数为0时,自动恢复配置初值
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//通道未被设置成? 诖娴侥诖婺J剑胙纺J较喽?
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_Init(DMA2_Channel4, &DMA_InitStructure);
        DMA_Cmd(DMA2_Channel3, ENABLE); //使能DMA的channel3
        DMA_Cmd(DMA2_Channel4, ENABLE); //使能DMA的channel4 
  
               
}

/**********正弦波初始化**********************/
//Wave1_Fre:        频率值(0~60 000)Hz
//Um                         :        电压峰值(0.0~1.5)V
/*******************************************/

void SineWave_Init(u16 Wave1_Fre,u16 Wave2_Fre,float Um)
{
        u32 f1,f2;
        f1=(u32)(72000000/sizeof(SineWave1_Value)*2/Wave1_Fre);//计算频率
        f2=(u32)(72000000/sizeof(SineWave2_Value)*2/Wave2_Fre);//计算频率
        SineWave1_Data(256,SineWave1_Value,Um);     //生成输出正弦波的波形表
        SineWave1_Data(256,SineWave2_Value,Um);     //生成输出正弦波的波形表
        SineWave_GPIO_Config();              //初始化io
        SineWave_TIM_Config(f1,f2);            //初始化定时器2
        SineWave_DAC_Config();              //配置DAC
        SineWave_DMA_Config();       //配置DMA
        TIM_Cmd(TIM2, ENABLE);             //开启定时器
        TIM_Cmd(TIM6, ENABLE);             //开启定时器

}





使用特权

评论回复
地板
hisungao|  楼主 | 2023-3-21 15:23 | 只看该作者
自己来回答了,用上面的例子改到STM32F103上试,两个DAC上到65K后也是开始乱搞,没搞明白这个DAC建立需要多长时间,感觉应该还是两个DAC来分的所以一超过就乱搞了。输出电压把缓冲打开也能到3.2V,只是这玩意啥负载都不带频率高了都不能满电压?有的人发的图片里是怎么能到满电压的呢?

使用特权

评论回复
5
zpwang| | 2023-4-2 19:15 | 只看该作者
我觉得吧,你需要得到2个DAC输出不同频率的话应该使用两个定时器分别去触发对应的DAC通道.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

52

帖子

0

粉丝