当前位置:   article > 正文

FPGA数字信号处理(九)Vivado FFT IP核实现_fpga fft ip核

fpga fft ip核

该篇是FPGA数字信号处理的第9篇,选题为DSP系统中极其常用的FFT运算。上篇介绍了Quartus环境下FFT IP核的使用“FPGA数字信号处理(八)Quartus FFT IP核实现https://blog.csdn.net/fpgadesigner/article/details/80690345 ”。本文将介绍在Vivado开发环境下使用Xilinx提供的FFT IP核进行FFT运算的设计。


IP核概述

这里写图片描述
Xilinx的FFT IP核属于收费IP,但是不需要像 Quartus那样通过修改license文件来破解。如果是个人学习,现在网络上流传的license破解文件在破解Vivado的同时也破解了绝大多数可以破解的IP核。只要在IP Catalog界面中Fast Fourier Transform的License状态为“Included”即可正常使用。


IP核参数设置

与Quartus中FFT IP核相比,Vivado的FFT IP核配置起来更复杂,功能也更强大。 打开主界面,左边是IP核的接口图(IP Symbol)、实现消耗的资源等信息(Implementation Details)和计算FFT所需的时间(Latency),右边是Configuration、Implementation和Detailed Implementation三个标签卡。

这里写图片描述
Vivado的FFT IP核支持多通道输入(Number of Channels)和实时更改FFT的点数(Run Time Configurable Transform Length)。Configuration标签下设置FFT的点数(Transform Length)和工作时钟(Target Clock Frequency),选择一种FFT结构,包括流水线Streaming、基4 Burst、基2 Burst和轻量级基2 Burst,计算速度和消耗的资源依次减少。
这里写图片描述
Implementation标签卡下设置FFT的数据格式为定点Fixed Point或浮点Float Point;设置输入数据的位宽和相位因子位宽(相当于旋转因子)。还有一些可选的附加信号。“Output Ordering”设置FFT计算结果以自然顺序(Nature Order)或位/数值反序(Bit/Digit Reversed Order)输出。
这里写图片描述
Detailed Implementation这个Tab中设置优化方式、存储的类型、是否使用DSP单元等与综合、实现有关的信息,比如可以选择复数乘法器和蝶形运算单元的实现结构。

设置完成后,系统会在Latency中显示出计算FFT所需的时间,如下图所示:
这里写图片描述
可以据此衡量计算速度是否满足设计需求,如不满足可以使用更好性能的FFT结构或选择可以提高计算速度的优化选项,消耗更多的资源来缩短计算周期。


FPGA设计

IP核的接口在Verilog HDL中进行设计时,一定要参考官方文档中给出的时序图。在IP核的配置界面点击“documentation”,可以找到IP核的user guide。 也可以在Xilinx官网或DocNav工具中搜索pg109,查阅FFT IP核的说明。Burst模式、自然顺序输出的时序图如下:
这里写图片描述
驱动接口时序的Verilog HDL示例代码如下所示:

`timescale 1ns / 1ps
//--------------------------------------------------------
//  使用Xilinx FFT IP核完成FFT运算
//--------------------------------------------------------
module Xilinx_FFT_Guide_liuqi(      

        input aclk,
        input aresetn,

        input [11:0]    input_data_ch1,
        output [23:0]   fft_real,
        output [23:0]   fft_imag,
        output reg [46:0]   amp,
        output fft_out_valid
);
    reg [11:0] input_data_ch1_reg;    
    wire [7:0] s_axis_config_tdata;
    reg s_axis_config_tvalid;

    wire s_axis_data_tready;
    reg [31:0] s_axis_data_tdata;
    reg s_axis_data_tvalid;
    reg s_axis_data_tlast;

    wire [47:0] m_axis_data_tdata;
    wire [15:0] m_axis_data_tuser;
    wire m_axis_data_tvalid;
    wire m_axis_data_tlast;
    reg [7:0]   cfg_cnt;
    reg [13:0]  sink_ctl_cnt;   
    reg [23:0]  fft_real,fft_imag; 
    reg fft_out_valid;
    wire    event_frame_started;
    wire    event_tlast_unexpected;
    wire    event_tlast_missing;
    wire    event_status_channel_halt;
    wire    event_data_in_channel_halt;
    wire    event_data_out_channel_halt;

    xfft_0 usr_FFT(

            .aclk(aclk),
            .aresetn(aresetn),

            .s_axis_config_tdata(s_axis_config_tdata),
            .s_axis_config_tvalid(s_axis_config_tvalid),
            .s_axis_config_tready(),

            .s_axis_data_tdata(s_axis_data_tdata),
            .s_axis_data_tvalid(s_axis_data_tvalid),
            .s_axis_data_tready(),
            .s_axis_data_tlast(s_axis_data_tlast),

            .m_axis_data_tdata(m_axis_data_tdata),
            .m_axis_data_tuser(m_axis_data_tuser),
            .m_axis_data_tvalid(m_axis_data_tvalid),
            .m_axis_data_tready(1'b1),
            .m_axis_data_tlast(m_axis_data_tlast),

            .event_frame_started(event_frame_started),
            .event_tlast_unexpected(event_tlast_unexpected),
            .event_tlast_missing(event_tlast_missing),
            .event_status_channel_halt(event_status_channel_halt),
            .event_data_in_channel_halt(event_data_in_channel_halt),
            .event_data_out_channel_halt(event_data_out_channel_halt)
    );   

//fft core config
    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            cfg_cnt <= 8'd0;
        else
        begin
            if(cfg_cnt < 8'd200)
                cfg_cnt <= cfg_cnt + 1'b1;
            else
                cfg_cnt <= cfg_cnt;
        end
    end

    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            s_axis_config_tvalid <= 1'b0;
        else
        begin
            if(cfg_cnt < 8'd200)
                s_axis_config_tvalid <= 1'b1;
            else
                s_axis_config_tvalid <= 1'b0;
        end
    end
assign s_axis_config_tdata = 8'd1;

/fft sink_in ctl/
    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            s_axis_data_tdata <= 32'b0;
        else
            s_axis_data_tdata <= {20'd0,input_data_ch1};
    end

    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            sink_ctl_cnt <= 14'd8194;
        else if(s_axis_config_tvalid)
            sink_ctl_cnt <= 14'd0;
        else if(sink_ctl_cnt == 14'd8192)
            sink_ctl_cnt <= 14'd1;
        else
            sink_ctl_cnt <= sink_ctl_cnt + 1'b1;
    end 

    //s_axis_data_tvalid
    always@(posedge aclk or negedge aresetn)
    begin
        if(!aresetn)
            s_axis_data_tvalid <= 1'b0;
        else if(sink_ctl_cnt < 14'd1)
            s_axis_data_tvalid <= 1'b0;
        else if(sink_ctl_cnt < 14'd2049)
            s_axis_data_tvalid <= 1'b1;
        else
            s_axis_data_tvalid <= 1'b0;
    end

    //s_axis_data_tlast
    always@(posedge aclk or negedge aresetn)
        begin
        if(!aresetn)
            s_axis_data_tlast <= 1'b0;
        else
        begin
            if(sink_ctl_cnt == 14'd2048)
                s_axis_data_tlast <= 1'b1;
            else
                s_axis_data_tlast <= 1'b0;
        end
    end
/fft sink_in ctl/    
    always@(posedge aclk)
    begin
        fft_real <= m_axis_data_tdata[23:0];
    end

    always@(posedge aclk)
    begin
        fft_imag <= m_axis_data_tdata[47:24];
    end

    always@(posedge aclk)
    begin
        fft_out_valid <= m_axis_data_tvalid;
    end

    /********** 计算频谱的幅值信号 **********/

    wire signed [45:0] xkre_square, xkim_square;
    assign xkre_square = fft_real * fft_real;
    assign xkim_square = fft_imag * fft_imag;

    always @(posedge aclk)
      amp <= xkre_square + xkim_square;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168

注意FFT计算结果输出的实部和虚部供用m_axis_data_tdata数据总线,因此在代码中需要截位分别得到实部和虚部。FFT计算结果的分析可以参考“FPGA数字信号处理(八)Quartus FFT IP核实现https://blog.csdn.net/fpgadesigner/article/details/80690345 ”中的内容。


仿真与工程下载

系统时钟(即FFT计算时钟)为50MHz,因此频谱范围为0~25MHz。使用MATLAB生成2MHz与15MHz的正弦波信号,分别写入txt文件。编写Testbench分别读取两个txt文件对两个单频信号做FFT分析,文件操作方法参考“Testbench编写指南(一)文件的读写操作”https://blog.csdn.net/fpgadesigner/article/details/80470972

首先仿真对2MHz信号的FFT分析。根据上文Latency中的估计,计算时间需要145μs,因此仿真需要运行到大约150μs以上。结果如下:
这里写图片描述
整个频谱的持续时间恰好是out_valid信号保持高电平的时间,很明显可以看到2MHz信号在频谱中对应的一个频率点。将txt文件替换为15MHz的信号,结果如下:
这里写图片描述
观察到15Mhz信号的频谱峰值位置明显比2MHz频率靠中,符合事实。

完整的Vivado工程(含testbench仿真)可以在这里下载:https://download.csdn.net/download/fpgadesigner/10478838

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/669413
推荐阅读
相关标签
  

闽ICP备14008679号