Xilinx FFT ip核使用例程

近来开展FFT相关的研究,尝试了一下Xilinx 的FFT IP核,再此分享一下;

源码不上传了(关键代码文中已有),有需要的请在评论区留下邮箱。

本例子的框架为:

FFT IP核设置-->

MATLAB生成模拟的正弦波并保存在.coe文件中-->

实例化一个Block Memory generator 单口ROM读取.coe文件-->

建立Testbench读取ROM,并将其输出的数据 作为FFT IP核的输入-->

查看FFT ip核的输出,并于MATLAB对比。

一、使用工具

       Vivado 2018.3,FFT ip核 版本:V9.1;Block Memory generator IP核:V8.4

       Matlab;

二、FFT IP核配置

(1)设置为单通道FFT,变换长度设置为1024,FFT架构选择Radix-4;

(2)设置数据类型为定点数,位宽设置为16,那么输入数据格式fix16_15,Phase Factor Witch保持默认

特别注意,这个例子中的数据输出的顺序设置为了Natural,还可以设置为Reversed,本文后面会给出对比。

(3)其他设置保持默认即可。然后点击Finish,完成IP核的配置。

三、仿真数据生成

采用Matlab生成正弦波,频率为50 Hz和120Hz叠加,数据长度设置为2048,波形如下:

在Matlab中实现的FFT变换结果如下:

然后将时域数据保存为.coe格式,供后续Vidado仿真使用。

四、建立仿真

(1)上一步完成了模拟数据的生成,并保存为了.coe格式,本节介绍将.coe中的数据加载到单口ROM中。

新建一个Vivado Block Memory generator,本例中的版本为8.4。

比较简单,Memory type选择Single Port ROM;

数据位宽与MATLAB保存的coe一致,设置为16,深度足够即可,coe中有2048个数据,再此设置深度大于2048

选择保存的.coe文件。

(2)TestBench

实例化两个IP:

ROM your_instance_name (
  .clka(clk),    // input wire clka
  .ena(ena),      // input wire ena
  .addra(addra),  // input wire [15 : 0] addra
  .douta(douta)  // output wire [15 : 0] douta    延时2个时钟输出
);

xfft_0 xfft_tb(
  .aclk(clk),                                              // input wire aclk
  .aresetn(aresetn),                                        // input wire aresetn

  .s_axis_config_tdata(s_axis_config_tdata),                // input wire [15 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(s_axis_config_tvalid),              // input wire s_axis_config_tvalid
  .s_axis_config_tready(s_axis_config_tready),                                  // output wire s_axis_config_tready
  
  .s_axis_data_tdata(s_axis_data_tdata),                    // input wire [31 : 0] s_axis_data_tdata
  .s_axis_data_tvalid(s_axis_data_tvalid),                  // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready),                                      // output wire s_axis_data_tready
  .s_axis_data_tlast(s_axis_data_tlast),                    // input wire s_axis_data_tlast
  
  .m_axis_data_tdata(m_axis_data_tdata),                    // output wire [31 : 0] m_axis_data_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid),                  // output wire m_axis_data_tvalid
  .m_axis_data_tlast(m_axis_data_tlast),                    // output wire m_axis_data_tlast
  .event_frame_started(event_frame_started),                // output wire event_frame_started
  .event_tlast_unexpected(event_tlast_unexpected),          // output wire event_tlast_unexpected
  .event_tlast_missing(event_tlast_missing),                // output wire event_tlast_missing
  .event_data_in_channel_halt(event_data_in_channel_halt)  // output wire event_data_in_channel_halt
);

设置数据流程,从ROM取出,然后输入到FFT,这段设置最为关键,要和IP核的时序图对应。

always @(posedge clk)
begin
    if(!aresetn)
        cnt <= 0;
    else
    begin
        cnt <= cnt + 1'b1;
        if(cnt == 0)
            s_axis_config_tvalid <= 1'b1;
        else if(cnt == 3)
            s_axis_config_tvalid <= 1'b0;
        else if(cnt == 5)    //ROM开始读出数据
            ena <= 1'b1;
        else if(cnt == 7)    //开始传输数据
            s_axis_data_tvalid <= 1'b1;
        else if(cnt == MAX_SIZE + 7)
            s_axis_data_tlast <= 1'b1;
        else if(cnt == MAX_SIZE + 8)
        begin
            s_axis_data_tvalid <= 1'b0;
            s_axis_data_tlast <= 1'b0;
        end
    end
end

注意:

FFT s_axis_config_tdata的设置,此处需要特别注意,IP核手册中有详细的解释,NFFT plus padding和CP_LEN plus padding仅在IP核设置了run time configurable transform point size有效,本例子没有设置,因此s_axis_config_tdata的最低为FWD/INV,这个Bit设置为1表示FFT,设置为0表示IFFT,此处设置为1。

SCALE_SCH也是需要特别注意的地方,IP核手册P25有详细解释。

wire [15 : 0] s_axis_config_tdata;
assign s_axis_config_tdata = 16'b0000_0_00_00_00_01_01_1;      //10bit + 1bit(FFT/IFFT)

然后是FFP IP核输出数据的处理,比较简单,分成Im和Re两部分。

四、仿真结果

仿真结果如下:

发布了29 篇原创文章 · 获赞 20 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/u013215852/article/details/105345952