FFT Vivado IP核實現

蓉&&蓉發表於2020-11-09

1、首先用matlab產生16bit二進位制正弦訊號資料,存入rom:

%設定引數
fi=5000;
L=1024;
N=16;
fs=20000;

%產生訊號
t=0:1/fs:(L-1)/fs;
theta=rand()*2*pi;
si=sin(2*pi*fi*t+theta);

f_s=si/max(abs(si));
Q_s=round(f_s*(2^(N-1)-1));

fid=fopen('C:\Users\HLPC\Desktop\Sin.txt','w');
for k=1:length(Q_s)
    B_s=dec2bin(Q_s(k)+(Q_s(k)<0)*2^N,N);
    for j=1:N
        if B_s(j)=='1'
            tb=1;
        else
            tb=0;
        end
        fprintf(fid,'%d',tb);
    end
    fprintf(fid,'\r\n');
end
fprintf(fid,';');
fclose(fid);

2、將資料存入rom ip核中
rom核的應用見:https://blog.csdn.net/qq_39005414/article/details/109552835
在這裡插入圖片描述
3、FFT ip核配置
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

`timescale 1ns / 1ps
module rom_fft(
    input sys_clk_n,
    input sys_clk_p,
    input rst_n,
    output [9:0] a,
    output reg [15:0]data_i,
    output m_axis_data_tvalid,  
    output [63:0] data_o,
    output reg [26:0]fft_re,
    output reg [26:0]fft_im,
    output reg [54:0]fft_amp
    );
wire clk;    
wire [15:0]spo;
reg s_axis_config_tvalid;   
wire s_axis_config_tready; 
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
wire m_axis_data_tlast;
wire s_axis_data_tready;
wire [63:0] m_axis_data_tdata;
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;
reg cnt_flag;
reg [10:0]cnt;
wire [53:0] xkre_square, xkim_square;
assign data_o =  m_axis_data_tdata;   
IBUFDS CLK(
    .I(sys_clk_n),
    .IB(sys_clk_p),
    .O(clk)   
);

xfft_0 your_instance_name (
  .aclk(clk),                                                // input wire aclk
  .aresetn(rst_n),
  .s_axis_config_tdata(8'd1),                  // 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({16'd0,data_i}),                      // 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(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
); 

reg [9:0] cnt1;
always @(posedge clk)begin
    if(~rst_n)
        cnt1 <= 1'b0;
    else if(cnt1 < 10'd200)
        cnt1 <= cnt1 + 1'b1;
end

always @(posedge clk)begin
    if(~rst_n)
        cnt_flag <= 1'b0;
    else if(s_axis_config_tvalid)
        cnt_flag <= 1'b1;
end

always @(posedge clk)begin
    if(~rst_n)
        s_axis_config_tvalid <= 1'b0;
    else if(cnt1 < 10'd200)
        s_axis_config_tvalid <= 1'b1;  
    else
        s_axis_config_tvalid <= 1'b0;  
end

always @(posedge clk)begin
    if(~rst_n)
        cnt <= 11'd0;
    else if(cnt_flag  )
        if(cnt <= 11'd1023)
            cnt <= 11'd1 + cnt;
        else
            cnt <= cnt;
    else
        cnt <= 11'd0;        
end

always @(posedge clk)begin
    if(~rst_n)
        s_axis_data_tvalid <= 1'b0;
    else if(cnt_flag && cnt <= 11'd1023)
        s_axis_data_tvalid <= 1'b1;
    else  
        s_axis_data_tvalid <= 1'b0;   
end

always @(posedge clk)begin
    if(~rst_n)
        s_axis_data_tlast <= 1'b0;
    else if(cnt == 11'd1023)
        s_axis_data_tlast <= 1'b1;
    else  
        s_axis_data_tlast <= 1'b0;   
end

always @(posedge clk)begin
    if(~rst_n)
        fft_im <= 27'd0;    
    else  
        fft_im <= data_o[58:32];   
end
always @(posedge clk)begin
    if(~rst_n)
        fft_re <= 27'd0;    
    else  
        fft_re <= data_o[26:0];   
end

mult_gen_0 your_instance_name3 (
  .CLK(clk),  // input wire CLK
  .A(fft_re),       // input wire [26 : 0] A
  .B(fft_re),       // input wire [26 : 0] B
  .P(xkre_square)  // output wire [53 : 0] P
);

mult_gen_0 your_instance_name4 (
  .CLK(clk),  // input wire CLK
  .A(fft_im),       // input wire [26 : 0] A
  .B(fft_im),       // input wire [26 : 0] B
  .P(xkim_square)  // output wire [53 : 0] P
);

always @(posedge clk)
   if(~rst_n)
      fft_amp <= 55'd0;
   else
      fft_amp <= xkre_square + xkim_square;

dist_mem_gen_0 your_instance_name1 (
  .a(a),                // input wire [9 : 0] a
  .clk(clk),            // input wire clk
  .qspo_rst(~rst_n),  // input wire qspo_rst
  .qspo(spo)          // output wire [15 : 0] qspo
);  

assign a = cnt;        
 always@(posedge clk or negedge rst_n)begin
    if(~rst_n )
        data_i <=  16'd0;
    else if(a <= 10'd1023)
        data_i <= spo; 
    end

endmodule

testbench模擬

module vtf_test(

    );
    
wire sys_clk_n;      
reg sys_clk_p; 
reg rst_n;
wire [15:0] data_i;
wire  [63:0] data_o;
wire  [26:0] fft_re;
wire  [26:0] fft_im;
wire  [54:0] fft_amp;
wire [9:0] a;
wire clk;
wire m_axis_data_tvalid;

rom_fft u_rom_fft(
    .sys_clk_n(sys_clk_n),
    .sys_clk_p(sys_clk_p),
    .rst_n(rst_n),
    .a(a),
    .data_i(data_i),
    .m_axis_data_tvalid(m_axis_data_tvalid),
   .data_o(data_o),
   .fft_re(fft_re),
   .fft_im(fft_im),
   .fft_amp(fft_amp)
    );
    
  
initial begin
    rst_n = 0;
    sys_clk_p = 0;
    #20;
    rst_n = 1;
    #2000000;
end

IBUFDS CLK(
    .I(sys_clk_n),
    .IB(sys_clk_p),
    .O(clk)   
);

integer file_out;
initial 
begin
   //檔案放置在"工程目錄\simulation\modelsim"路徑下                                                  
	file_out = $fopen("out.txt");
	if(!file_out)
		begin
			$display("could not open file!");
			$finish;
		end
end
always @(posedge clk)begin    
    if(m_axis_data_tvalid)
	   $fdisplay(file_out,"%d",fft_amp);
end

integer file_out1;
initial 
begin
   //檔案放置在"工程目錄\simulation\modelsim"路徑下                                                  
	file_out1 = $fopen("out1.txt");
	if(!file_out)
		begin
			$display("could not open file!");
			$finish;
		end
end
always @(posedge clk)begin
    if((a>0) && (a<10'd1023))
	   $fdisplay(file_out1,"%d",data_i);
end

always #5 sys_clk_p=~sys_clk_p;  
assign  sys_clk_n=~sys_clk_p; 

endmodule

模擬結果
在這裡插入圖片描述
4、將結果輸出和matlab fft後的結果對比:

subplot(2,1,1)
cstr = textread('D:\fpga_test\rom_fft\rom_fft.sim\sim_1\behav\xsim\out.txt','%d');
plot(cstr)
subplot(2,1,2)
cstr1 = textread('C:\Users\HLPC\Desktop\Sin.txt','%d');
plot(abs(fft(cstr1)))

在這裡插入圖片描述

相關文章