Xilinx FFT IP核 调试经验

挺多人问我原工程,我就把它打包放网盘了,需要自取。
链接:https://pan.baidu.com/s/1nDqoB2a1y-TZJhI3lfHXtQ
提取码:tm26
———————————————————————以下原文————————————————————————————

23333,这两天做FBMC FPGA的实现 入了Xilinx的FFT IP的坑,在此把遇到的痛苦经历记录下来,如有和我情况一样的拿走不谢。 话不多说,直接上经历。

1.FFT IP核无法进行8/16/32点的配置,意味着最少从64点起步。我不知道是不是版本的问题,反正我和我同学的都是这样,脑阔疼。 我是2016.3的vivado版本。

2.关于
在这里插入图片描述

切记,RESET一定要勾选,一定要,一定要!话说三遍,你不勾选自己去看后果吧,上电复位最少三个时钟切记。 关于这个XK_INDEX的话,这个会使得你在后续FFT处理中非常的方便。

3.关于s_axis_config_tdata,这个是FFT的配置数据,形式在FFT IP Core说明书中是有的,只不过看的有点脑阔疼。告诉你个小窍门
在这里插入图片描述
看到了吗,在这个页面下,关于配置数据的格式是有定义的 ,你根据你的定义去进行修改即可。

4.关于某时刻你发现输入的数据一切完好,但是输出却是XXXXXXX,mmp,很烦了。
这是因为你FFT例化的问题,例化的时候一定要例化好,把原生的文件原生的端口一个不落的加进来

fft fft_module (
  .aclk(aclk),                                                // input wire aclk
  .aresetn(reset),                                          // 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_tready(m_axis_data_tready),                    // input wire m_axis_data_tready
  .m_axis_data_tlast(m_axis_data_tlast),                      // output wire m_axis_data_tlast
  .m_axis_data_tuser(m_axis_data_tuser),                      // output wire [7 : 0] m_axis_data_tuser
  
   .event_fft_overflow(event_fft_overflow),                    // output wire event_fft_overflow
  .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_status_channel_halt(event_status_channel_halt),      // output wire event_status_channel_halt
  .event_data_in_channel_halt(event_data_in_channel_halt),    // output wire event_data_in_channel_halt
  .event_data_out_channel_halt(event_data_out_channel_halt)  // output wire event_data_out_channel_halt
);
这样一般就ok了。

5.关于AXIS协议。FFT 这么多线是不是头疼,其实如果你细心的话你会发现上面那个代码块被我分成了5部分。第一部分是时钟和复位,不再赘述,接下来是配置数据,输入端和输出端,最后是提示的一些信息。其中配置数据输入端和输出端是一样的协议。除了data外还有三根线axis_data_tvalid,axis_data_tready,axis_data_tlast。axis_data_tvalid是说向对方表示我数据准备好了,你可以进行传送了,axis_data_tready是对方向你说他数据准备好了可以传送了。通常在这两种都完成的情况下,数据就可以进行传送了,最后一根线axis_data_tlast是在最后一个数据时这个数据线拉高i,提示对方说我的数据传输完了。是这个意思。恩对。

6.关于FFT和IFFT。不得不说FFT蛮准的,跟MATLAB基本差不多。但是IFFT就emmmmm…先看一组数据
这个是仿真数据
在这里插入图片描述
这个是MATLAB做出来的结果
在这里插入图片描述
是不是感觉差别好大。。。 我心态都快炸了,感觉两个数据一点都不一样啊。但是你细心看,仿真得到的数据都等于MATLAB做出的数据乘以128,128是我的FFT点数,这样的话基本就ok了。原来这样子,IFFT做出来的结果统一要进行除以FFT点数的运算,才能得到和MATLAB一样的结果。

7.关于缩放因子。是这样的,比如MATLAB求出来的这个数是56,如果你的缩放因子是6’b000011的话,那你仿真得到的结果就是56/(2^3)=7.

行,大概就是这样子,有什么问题我再补充吧。接下来上一下测试代码和matlab生成需要变换数据文件的代码。要的,拿去。

//测试代码
`timescale 1ns / 1ps
module tb();

reg[15:0] memory[0:127];//申请128个16位的存储单元
reg[11:0] n;
initial
	begin
		$readmemb("F:/mem.txt",memory); //读取file1.txt中的数字到memory
	    for(n=0;n<128;n=n+1)   //把八个存储单元的数字都读取出来,若存的数不到八个单元输出x态,程序结果中会看到
		  $display("%b",memory[n]);
	end

reg aclk;
reg reset;
reg s_axis_config_tvalid;
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
reg m_axis_data_tready;
reg [15:0] s_axis_config_tdata;
reg [63:0] s_axis_data_tdata;

// Outputs
wire s_axis_config_tready;
wire s_axis_data_tready;
wire m_axis_data_tvalid;
wire m_axis_data_tlast;
wire event_frame_started;
wire event_tlast_unexpected;
wire event_tlast_missing;
wire event_status_channel_halt;
wire event_fft_overflow;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;
wire [63: 0] m_axis_data_tdata;
wire [7:0]  m_axis_data_tuser;

//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
fft fft_module (
  .aclk(aclk),                                                // input wire aclk
  .aresetn(reset),                                          // 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_tready(m_axis_data_tready),                    // input wire m_axis_data_tready
  .m_axis_data_tlast(m_axis_data_tlast),                      // output wire m_axis_data_tlast
  .m_axis_data_tuser(m_axis_data_tuser),                      // output wire [7 : 0] m_axis_data_tuser
  
   .event_fft_overflow(event_fft_overflow),                    // output wire event_fft_overflow
  .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_status_channel_halt(event_status_channel_halt),      // output wire event_status_channel_halt
  .event_data_in_channel_halt(event_data_in_channel_halt),    // output wire event_data_in_channel_halt
  .event_data_out_channel_halt(event_data_out_channel_halt)  // output wire event_data_out_channel_halt
);

// generate clk
always #5 aclk =! aclk;

initial
begin
		// Initialize Inputs
		aclk = 0;
		reset = 0;
		s_axis_config_tvalid = 0;
		s_axis_config_tdata = 0;
		s_axis_data_tvalid = 0;
		s_axis_data_tdata = 0;
		s_axis_data_tlast = 0;
		m_axis_data_tready = 0;
	      
	    #200;
	    reset = 1;
        // Wait 100 ns for global reset to finish
        #100;
        m_axis_data_tready = 1;
        s_axis_config_tvalid = 1;
        s_axis_config_tdata = 15'b0000000000000000; // FFT 
        s_axis_data_tdata = 64'b0;	
        s_axis_data_tvalid = 0;
        
     
       #1000;    
          for(n=0;n<128;n=n+1)
              begin
                #10
                s_axis_data_tvalid <= 1;
                s_axis_data_tdata <= {{48'b0},memory[n]};
                $display("mem_a[%d] = %h", n, memory[n]);
                if(n== 127)
                    s_axis_data_tlast <= 1;
                else
                    s_axis_data_tlast <= 0;
               end
      
        
        #10;
        s_axis_data_tlast <= 0;
        s_axis_data_tdata = 64'h0000;    
        s_axis_data_tvalid = 0;
  
 end
 
wire [31:0] m_data_im;
wire [31:0] m_data_re; 
 assign m_data_im = m_axis_data_tdata[63:32];
 assign m_data_re = m_axis_data_tdata[31:0];

endmodule

%MATLAB生成数据
table = 0:127;
trans_table = str2num(dec2bin(table));

add = fopen('F:\mem.txt','w+');

fprintf(add,'%016d \n',trans_table);

fclose(add);

接着,是在FPGA上实现的代码,我前边有一个FIR,从RAM里读数据给FFT然后再做运算,可以参考。

`timescale 1ns / 1ps
module FFT(
    //-------------------------输入-------------------------------------------------------------
    input               CLK_100M,
    input               reset,
    
    input    [31:0]     FFT_Data,
    input               FFT_im_re,          //前两个数是虚实还是实数虚数
    input    [11:0]     FIR_add,
    output              FFT_input_start,
    
    output reg  [11:0]     FFT_Data_address,  //需要第几个地址
    output      [15:0]     FFT_ans_add,  //输出地址
    output      [31:0]     FFT_ans_Data_re, //输出实部
    output      [31:0]     FFT_ans_Data_im, //输出虚部
    output                  FFT_ans_valid     //FFT输出有效
);
//----------------------------------------------------------------------------------------------------
//                  IFFT例化
wire                            s_axis_config_tready;

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

wire         [63:0]              m_axis_data_tdata;
wire         [15:0]              m_axis_data_tuser;
wire                             m_axis_data_tvalid;
reg                              m_axis_data_tready;
wire                             m_axis_data_tlast;

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;

IFFT IFFT_Module (
  .aclk(CLK_100M),                                                // input wire aclk
  .aresetn(reset),                                               // input wire aresetn
  
  .s_axis_config_tdata(16'd0),                                // input wire [15 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(1'b1),                                // 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 [63 : 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 [63 : 0] m_axis_data_tdata
  .m_axis_data_tuser(m_axis_data_tuser),                      // output wire [15 : 0] m_axis_data_tuser
  .m_axis_data_tvalid(m_axis_data_tvalid),                    // output wire m_axis_data_tvalid
  .m_axis_data_tready(1'b1),                                  // input wire m_axis_data_tready
  .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_status_channel_halt(event_status_channel_halt),      // output wire event_status_channel_halt
  .event_data_in_channel_halt(event_data_in_channel_halt),    // output wire event_data_in_channel_halt
  .event_data_out_channel_halt(event_data_out_channel_halt)  // output wire event_data_out_channel_halt
);
//---------------------------------------------------------------------------------------------------------------
//                      开始进行IFFT   
reg                 one_end_flag;
always @ (posedge CLK_100M)
begin
    if(FFT_Data_address == 12'd4095)
        s_axis_data_tvalid <= 1'b0;
    else if((FIR_add==12'd4095)&one_end_flag)
        s_axis_data_tvalid <= 1'b1;
end
//---------------------------------------------------------------------------------------------------------------
//                      只进行一帧

always @ (*)
begin
    if(FFT_Data_address == 12'd4095)
        one_end_flag = 1'b0;
    else if(FIR_add==12'd4094)
        one_end_flag = 1'b1;
end
//---------------------------------------------------------------------------------------------------------------
//                      生成取数地址
reg [11:0]  FFT_Data_address_n;
always @ (*)
begin
    if(FFT_Data_address == 12'd4095)
        FFT_Data_address_n = 12'd0;
    else if(s_axis_data_tvalid&one_end_flag)
        FFT_Data_address_n = FFT_Data_address +1'b1;
    else
        FFT_Data_address_n = 12'd0;
end

always @ (posedge CLK_100M or negedge reset)
begin
    if(!reset)
        FFT_Data_address = 12'd0;
    else
        FFT_Data_address <= FFT_Data_address_n ;
end
//---------------------------------------------------------------------------------------------------------------
//                      虚实选择
always @ (posedge CLK_100M)
begin
    if(FFT_im_re)
        begin
            if(FFT_Data_address[0])
                s_axis_data_tdata <= {FFT_Data,32'b0};
            else
                s_axis_data_tdata <= {32'b0,FFT_Data};
        end
     else
         begin
             if(FFT_Data_address[0])
                 s_axis_data_tdata <= {32'b0,FFT_Data};
             else
                 s_axis_data_tdata <= {FFT_Data,32'b0};
         end
end

//---------------------------------------------------------------------------------------------------------------
//                      最后一帧拉高
always @ (posedge CLK_100M or negedge reset)
begin
    if(!reset)
         s_axis_data_tlast <= 1'b0;
    else
        begin
            if(FFT_Data_address==12'd4094)
                s_axis_data_tlast <= 1'b1;
            else
                s_axis_data_tlast <= 1'b0;
        end
end

//---------------------------------------------------------------------------------------------------------------
//                      输出端口赋值
assign FFT_ans_add = m_axis_data_tuser;
assign FFT_ans_Data_re = m_axis_data_tdata[31:0];
assign FFT_ans_Data_im = m_axis_data_tdata[31:0];
assign FFT_ans_valid = m_axis_data_tvalid;
assign FFT_input_start = s_axis_data_tvalid;

initial
begin
    s_axis_data_tlast = 1'b0;
    s_axis_data_tdata = 64'd0;
    s_axis_data_tvalid = 1'b0;
    m_axis_data_tready = 1'b0;
    FFT_Data_address_n = 12'd0;
    one_end_flag = 1'b0;
end

endmodule

最后,吐槽下CSDN难用的编辑器,让我编辑这篇文章编辑了两遍,谢谢你。

  • 19
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
### 回答1: Vivado FFT IP核Xilinx公司提供的一种用于高性能快速傅里叶变换(FFT)的可编程逻辑器件,可用于信号处理、通信系统、雷达、音频处理和图像处理等领域。 Vivado FFT IP核的主要功能是实现快速傅里叶变换,这是一种将时域信号转换为频域信号的数学技术。FFT是一种高效的算法,能够在较短的时间内对信号进行频谱分析和频率测量。Vivado FFT IP核提供了多种FFT算法,包括基于蝶形算法、流水线和并行化等技术,可以根据应用的需求选择适合的算法。 Vivado FFT IP核提供了多种配置选项,可以实现不同数据宽度、数据精度和时域点数的FFT计算。用户可以通过Vivado设计环境来配置和生成FFT IP核,方便地集成到自己的设计中。IP核的接口支持AXI4-Stream和AXI4-Lite等标准接口,与其他系统组件进行数据交换。 通过使用Vivado FFT IP核,用户可以在FPGA上快速实现高性能的FFT计算,提高系统的性能和效率。IP核的可编程性使得用户可以根据应用需求进行定制,并且可以随着设计的迭代进行功能增强或优化。此外,使用IP核还可以减少设计开发时间和复杂度,提高设计的可重用性。 综上所述,Vivado FFT IP核是一种用于快速傅里叶变换的可编程逻辑器件,具有灵活的配置选项和高性能的计算能力。使用该IP核可以快速实现高性能的FFT计算,提高系统的性能和效率。 ### 回答2: Vivado FFT IP核Xilinx公司提供的一种用于快速傅里叶变换(FFT)运算的IP核FFT是一种用于信号频谱分析的算法,广泛应用于数字信号处理领域。Vivado FFT IP核通过硬件加速的方式,实现了高效的FFT计算。 Vivado FFT IP核具有以下主要特点: 1. 高性能:Vivado FFT IP核使用专门的FFT硬件来执行计算,速度比软件实现的FFT更快。它能够在很短的时间内完成大规模FFT计算。 2. 可定制性:Vivado FFT IP核提供了许多可定制的选项。用户可以根据具体的需求选择不同的FFT大小、输出数据宽度、输入数据格式等。这样有助于优化设计,提高系统整体性能。 3. 多种接口:Vivado FFT IP核支持多种接口,如AXI4-Stream接口、AXI4-Lite接口等,方便与其他IP核或外部系统进行连接。 4. 低功耗:Vivado FFT IP核经过优化设计,能够在低功耗下运行,节约能源消耗。 Vivado FFT IP核的应用范围广泛。在通信领域中,它可以用于信号解调、频谱分析、通道估计等。在图像处理领域中,它可以用于图像压缩、图像增强等。此外,在雷达、声音处理、金融分析等其他领域也有广泛的应用。 Vivado FFT IP核的使用步骤相对简单。首先,在Vivado设计工具中导入该IP核,在设计中进行配置和参数设置。然后,将IP核与其他系统进行连接,并根据需要编写相应的控制和数据处理逻辑。最后,生成比特流文件(bitstream)并下载到目标设备中进行验证和调试。 总之,Vivado FFT IP核是一种高性能、可定制的FFT计算IP核,广泛应用于信号处理等领域,为设计人员提供了快速可靠的FFT计算解决方案。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值