[原创] 【雅特力AT-START-F435】基于DSP库实现DAC波形->FFT->RFFT回显

zhangbaoyin   2023-7-7 21:10 楼主

【雅特力AT-START-F435】基于DSP库实现DAC波形->FFT->RFFT回显

前言

    本项目为课程设计:DAC+ADC+FFT。DAC使用示波器管观察波形,并连接到本机ADC使用fft还原信号,串口打印信息到电脑上。

image.png

  • DAC和ADC采样都使用定时器触发的方式
  • DAC只要开始后就不会停止,作为信号源从PA4输出
  • ADC采样使能 DMA_CH1 通道,当DMA搬移了足够多 (这里设置为了1024) 个采样点之后,停止ADC触发定时器计时,ADC采样结束。
  • 采样完成后,使用 FFT 进行快速傅里叶正变换,得到幅频响应,串口输出幅频响应。
  • 通过 RFFT 快速傅里叶逆变换,将幅频曲线逆变换为信号,通过串口调试助手显示还原后的波形

 

 

一、DAC波形

void DAC_Config(void)
{
	gpio_init_type  gpio_init_struct = {0};
	dma_init_type dma_init_struct;
	crm_clocks_freq_type crm_clocks_freq_struct = {0};
	
	crm_periph_clock_enable(CRM_TMR2_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_DAC_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	
	//获取DAC电压波形
	GetWave(0);

  /* once the dac is enabled, the corresponding gpio pin is automatically
     connected to the dac converter. in order to avoid parasitic consumption,
     the gpio pin should be configured in analog */
  gpio_init_struct.gpio_pins = GPIO_PINS_4;
  gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG;
  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init(GPIOA, &gpio_init_struct);

  /* get system clock */
  crm_clocks_freq_get(&crm_clocks_freq_struct);

  /* (systemclock/(systemclock/1000000))/1000 = 1KHz */
  tmr_base_init(TMR2, DACDUTY-1, (crm_clocks_freq_struct.sclk_freq/1000000 - 1));
  tmr_cnt_dir_set(TMR2, TMR_COUNT_UP);

  /* primary tmr2 output selection */
  tmr_primary_mode_select(TMR2, TMR_PRIMARY_SEL_OVERFLOW);

  /* dac1 configuration */
  dac_trigger_select(DAC1_SELECT, DAC_TMR2_TRGOUT_EVENT);

  dac_trigger_enable(DAC1_SELECT, TRUE);

  dac_wave_generate(DAC1_SELECT, DAC_WAVE_GENERATE_NONE);

  dac_output_buffer_enable(DAC1_SELECT, TRUE);

  dac_dma_enable(DAC1_SELECT, TRUE);

  /* dma1 channel2 configuration */
  dma_reset(DMA1_CHANNEL2);
  dma_init_struct.buffer_size = TEST_LENGTH_SAMPLES;
  dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  dma_init_struct.memory_base_addr = (uint32_t)dactestInput_q15;
  dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
  dma_init_struct.memory_inc_enable = TRUE;
  dma_init_struct.peripheral_base_addr = (uint32_t)(DAC_BASE+0x008);//0x40007410
  dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
  dma_init_struct.peripheral_inc_enable = FALSE;
  dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
  dma_init_struct.loop_mode_enable = TRUE;
  dma_init(DMA1_CHANNEL2, &dma_init_struct);

  /* enable dmamux function */
  dmamux_enable(DMA1, TRUE);
  dmamux_init(DMA1MUX_CHANNEL2, DMAMUX_DMAREQ_ID_DAC1);

  dma_channel_enable(DMA1_CHANNEL2, TRUE);

  /* enable dac1: once the dac1 is enabled, pa.04 is
     automatically connected to the dac converter. */
  dac_enable(DAC1_SELECT, TRUE);

  /* enable tmr2 */
  tmr_counter_enable(TMR2, TRUE);
}
  1. 初始化GPIO PA4 为DAC的输出口
  2. 使能定时器 TMR2 。设置分频后的频率为1Mhz,然后根据period选择触发Duty 。例如,设置触发Duty为10,那么就是10us触发一次,100kHz触发频率
  3. 产生波形函数,产生固定频率的周期波,这里设置为
    /* 波形是由直流分量、50Hz 正弦波、25Hz余弦波组成,波形采样率 1024 ,初始相位 0 */
    testInput_f32[i] = 1 + 
    		0.5*arm_sin_f32( 2*3.1415926f*50*i/TEST_LENGTH_SAMPLES ) + 
    		1.0*arm_cos_f32( 2*3.1415926f*25*i/1024 );
  4. 波形产出的是 float32_t 的类型,要进行波形放大,并且转化为 12bit 位的数据格式
    /* 波形极值,确定放大倍数 */
    	arm_min_f32(testInput_f32, TEST_LENGTH_SAMPLES, &minData, NULL);
    	arm_max_f32(testInput_f32, TEST_LENGTH_SAMPLES, &maxData, NULL);
    	mulScale = (0x0FFF)*1.0 / (maxData-minData);
    	/* 上移波形,放大 */
    	for(i=0; i<TEST_LENGTH_SAMPLES; ++i) {
    		dactestInput_q15[i] = ( testInput_f32[i]-minData ) * mulScale;
    	}
  5. 使能DMA,开启DAC输出。

 

 

二、ADC采样

    adc采样可以参考一下这两边文章:

【新提醒】【雅特力AT-START-F435】ADC软触发always、DACTmr2触发、DMA,驱动LED被钳位1.54V问题 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn)

【新提醒】【雅特力AT-START-F435】ADC采样速率测试5.33MSPS - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn)

需要修改的有:

  1. 使用 TMR1 触发ADC开始采集,值得注意的是,普通通道只能使用上升沿触发
  2. 根据采样定理,采样频率最好大于2倍信号最高频率,即ADCDuty应该最好小于DACDuty

 

三、FFT转换和RFFT转换

    因为采用了按键触发采样的方式,即按下按键的上升沿,开始采样1024个采样点。

    所以,

  1. 在按键中断服务函数中,开启ADC触发定时器;
    tmr_counter_enable(TMR1, TRUE);

     

  2. 在ADC的DMA通道全部搬移完成中断中,关闭ADC触发定时器
    tmr_counter_enable(TMR1, FALSE);

image.png

  • 转换的FFT幅频曲线存放到 testOutputMag_f32 数组中
  • 逆变换的函数图像存放到 testRfft_f32 数组中

 

 

四、转换结果查看

使用下面的信号进行DAC输出采样,

/* 波形是由直流分量、50Hz 正弦波、25Hz余弦波组成,波形采样率 1024 ,初始相位 0 */
testInput_f32[i] = 1 + 
		0.5*arm_sin_f32( 2*3.1415926f*50*i/TEST_LENGTH_SAMPLES ) + 
		1.0*arm_cos_f32( 2*3.1415926f*25*i/1024 );

FFT变换的幅频响应如下:

image.png

 (图 串口打印的幅频响应频率和幅值百分比)

image.png

  (图 幅频响应曲线)

image.png

(图 原信号.下RFFT还原的信号.上

 

 

 

009-DAC+ADC+FFT.zip (2.65 MB)
(下载次数: 15, 2023-7-7 21:10 上传)
 

 

 

回复评论 (4)

RFFT 快速傅里叶逆变换,将幅频曲线逆变换为信号,通过串口调试助手显示还原后的波形,这思路值得学习

点赞 (1) 2023-7-8 09:03

这个板子支持几路DAC啊  

在爱好的道路上不断前进,在生活的迷雾中播撒光引
点赞  2023-7-8 23:26
引用: Jacktang 发表于 2023-7-8 09:03 RFFT 快速傅里叶逆变换,将幅频曲线逆变换为信号,通过串口调试助手显示还原后的波形,这思路值得学习

大佬过奖

点赞  2023-7-8 23:32
引用: 秦天qintian0303 发表于 2023-7-8 23:26 这个板子支持几路DAC啊  

我记得是2个DAC通道输出 image.png  

点赞  2023-7-8 23:33
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复