基于Vivado的DDS和FIR核的使用

本文详细介绍了在FPGA中DDS(直接数字频率合成器)和FIR(有限impulseresponse)的配置过程,包括DDS的系统参数、硬件参数设置,以及FIR的Matlab设计和Vivado中的IP配置。通过实例展示了如何在FPGA中利用DDS产生正弦波并经过FIR滤波,实现实时信号处理。

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

DDS(Direct Digital Frequency Synthesizer)直接数字频率综合和FIR(Finite Impulse Response)有限脉冲响应在数字信号中是比较常见的几种之一。在这里就最近碰到的这两个在FPGA中的实现做个记录,也算是为将来有个回顾。

一、DDS

话不多说,直接上vivado中的DDS IP核的配置

①Configuration(配置项),可选择相位和正余弦输出,仅相位,仅正弦或余弦  3种中的其中一种,对于需要正交输出的,则选择第一个

②System Requirements(系统需求):时钟,通道数,操作模式,参数选择等

时钟:为给定输入的时钟频率

通道数:为给定的想要的输出通道数量,当通道数大于2时,每个通道所能使用的频率为输入频率的N分频。100/2=50M

操作模式:分为 标准模式  和 栅格模式

Parameter Selection(参数选择):系统参数 和 硬件参数,当配置项为相位生成器或 单个的正余弦时,仅可使用硬件参数。

System Parameter(系统参数)时,需要指定SFDR和频率精度。SFDR 设定输出宽度以及内部的总线宽度。

频率精度,以Hz为单位,指定最小频率分辨率,用于确定相位累加器及其相关相位增量PINC,相位偏移POFF值所用的相位宽度。根据下一个Noise shaping的选择,可以增加相位宽度,并且频率分辨率高于此处指定的分辨率。事实上,Noise Shaping 的设置采用auto即可。

Hardware Parameters(硬件参数)时,需要指定相位宽度和输出宽度

参数选择 用系统参数和硬件参数时,会有一个差别,即系统参数时,需要设置输出信号的频率,而硬件参数时,需要设置相位角增量值。相应的都是在计算输出信号的频率,一个是直接给定,另一个是通过相位角来计算的。

数据输出,当启用正弦或余弦时,数据输出有效。在新版本的IP核中,已经将输出合并到一个tdata中,以取代了以往单独的sine和cosine数据输出。

数据是通过符号位扩展来达到字节的边界的,且有效的数据位位于低位,符号位位于高位,对于单个的正弦或余弦,最低位即为对应的数据位,而正弦和余弦同时输出的数据,余弦数据位于低位。

上图中,表示了11位的有效数据,符号位扩展到了字节的边界位。

个人认为,DDS IP核的几个重点配置大部分都在了,在IP的具体配置中,对于前述的system parameter,则需要在后续的配置中指明输出信号的频率;而对于hardware parameter 则需要指明相位角增量这些参数,可参照后面给出的官方的配置文档。

当IP生成之后,剩下的就是将其例化到具体的模块里面去了。

二、FIR

至于什么叫FIR,这里就不过多说明了,请参照其他资料,csdn上这方面的东西还是挺多的。

在设计中,采用matlab联合vivado的方式实现FIR功能。那么就有几个步骤的工作需要做:

①在matlab中设计出符合频率响应特性的滤波器,并导出系数,将这些系数按照一定的量化格式给到FPGA;

②FPGA 通过将上述系数导入的IP中,并经由一些配置,实现IP核;

③FPGA中对IP核的例化,实现FIR功能;

下面开始上图。

在matlab中用fdatool进行滤波器的设计,如下

之后,切换成量化参数界面,更改为定点Fixed-point模式,并指定量化的位数

之后,点击target  --> coe文件,生成xilinx对应的coe文件。以便后续在FPGA 的IP中调用。

vivado中对IP的配置操作:

滤波选项:选择用coe文件(因为要使用前述matlab导出的系数),系数集 因为只有一个,所以设置为1,滤波类型选择 single rate,其余默认即可

通道规格:此处最重要的设置是设置采样率,时钟等。需要跟Matlab生成coe系数文件时所采用的设置保持一致。在这里将时钟与采样率设置成1:1的关系,否则会导致滤波结果中仍然会出现其他频率成分的信号,类似于“混叠”。图中中,设置的参数与matlab中的不一致,那是因为截图的时候不是同样的参数,

其余项的配置,后续就不一一列出了。

当IP配置完成后,剩下的就是例化IP,对其进行使用了。

三、编码开发

设计中通过DDS产生了2个正弦波信号,频率分别为250K和5M,将这两个信号相加作为FIR滤波器的输入,FIR设置的通带为1M,以期望滤除5M的信号,仅保留250K信号输出。

1、例化DDS

wire    data1_valid;
wire    data2_valid;

dds_sin dds_sin_250k (
  .aclk(clk_out1),                              // input wire aclk
  .aresetn(clk_locked),                        // input wire aresetn
  .m_axis_data_tvalid(data1_valid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(sin_data1)    // output wire [15 : 0] m_axis_data_tdata
);

dds_sin2 dds_sin2_5M (
  .aclk(clk_out2),                              // input wire aclk
  .aresetn(clk_locked),                        // input wire aresetn
  .m_axis_data_tvalid(data2_valid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(sin_data2)    // output wire [15 : 0] m_axis_data_tdata
);

2、例化加法器,实现求和

//加法运算
//wire    [16:0]  addr_data;
adder adder_inst (
  .A(sin_data1),      // input wire [15 : 0] A
  .B(sin_data2),      // input wire [15 : 0] B
  .CLK(clk_out2),  // input wire CLK
  .CE(1'b1),    // input wire CE
  .S(addr_data)      // output wire [16 : 0] S
);

3、例化FIR

//通过Matlab FDATOOL 工具进行FIR设计,导出coe文件
//此处对应的Fpass=1M,Fstop=2.5M
//需要注意的是,数据的格式,在FIR中输入输出数据均是以8位为边界的
//实际的IP中,输入需要16位,输出需要35位,IP中例化的则是16位和40位
wire    [39:0]  fir_out_tdata;
wire    m_axis_data_tvalid;
wire    s_axis_data_tready;

fir_compiler_0 fir_compiler_inst (
  .aclk(clk_out3),                              // input wire aclk
  
  .s_axis_data_tvalid(data2_valid && data1_valid),  // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),  // output wire s_axis_data_tready
  .s_axis_data_tdata({ {7{addr_data[16]}} ,addr_data}),    // input wire [23 : 0] s_axis_data_tdata
  
  .m_axis_data_tvalid(m_axis_data_tvalid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(fir_out_tdata)    // output wire [39 : 0] m_axis_data_tdata
);

assign fir_outdata = fir_out_tdata[35:0];

4、顶层设计

module Top_dds_fir(
    input   clk_i,
    input   rst_n,
    
    output  [15:0]  sin_data1,  //输出波形1
    output  [15:0]  sin_data2,  //输出波形2
    
    output  [16:0]  addr_data,  //输出相加后的波形3,3=1+2
    
//    output  [31:0]  mul_data,   //输出相乘后的波形
    output  [35:0]  fir_outdata //输出滤波后的波形
);

当然,还有一部分例化时钟IP的代码缺失,请自行补充吧。

四、仿真

仿真代码比较简单,模块例化、给个时钟,进行初始化设置等等。

module TB_top_dds_fir( );
reg     clk_i;
reg     rst_n;
wire    [15:0]  sin_data1;
wire    [15:0]  sin_data2;
wire    [16:0]  addr_data;
wire    [35:0]  fir_outdata;

Top_dds_fir Top_dds_fir(
    .clk_i(clk_i),
    .rst_n(rst_n),
    
    .sin_data1(sin_data1),
    .sin_data2(sin_data2),
    .addr_data(addr_data),
    .fir_outdata(fir_outdata)
);

initial begin
    //initial 
    clk_i = 1'b0;
    rst_n = 1'b0;
    
    #100;
    rst_n = 1'b1;        //100nS后,放开复位
        
    #20000;
    $finish;
    
end

always #10 clk_i = ~ clk_i; //产生50M时钟

endmodule

仿真结果:结果如下图所示。从图中可以看出,求和后的波形为两个波形的叠加,经fir后,将高频信号滤除了,仅保留了低频信号输出。

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值