Xilinx Vivado FFT IP使用步骤

1 介绍

        只作为本人调试笔记使用,如有错误,请指正,感谢。

2 生成IP

        软件版本基于2023.2。

        

使用ooc方式编译IP,会生成cmodel文件,可以直接在matlab中仿真使用:

3 编写HDL测试文件:

以512个数据长度为例:


module tb();

reg		clk250 = 1'b0;
always #2 clk250 <= ~clk250;

reg		nRst = 1'b0;

reg signed [15:0] mem_data_I[511:0];
reg signed [15:0] mem_data_O[0:511];
integer outputfile;
integer outputfile1;
reg	[8:0]	n;

initial begin
	clk250	<= 1'b0;
	nRst	<= 1'b0;
	#101
	nRst	<= 1'b1;
    $readmemh("G:/FFT/fft_ip_in.txt",mem_data_I);
	outputfile = $fopen("G:/FFT/fft_ip_out_re.txt","w");
	outputfile1 = $fopen("G:/FFT/fft_ip_out_im.txt","w");

	#23000
//	for(n=0;n<=511;n=n+1)  
//	$fwrite(outputfile,"%x\n",mem_data_O);
	$fclose(outputfile);
	$fclose(outputfile1);
end

reg		[9:0]		cnt = 'd0;


reg signed [31:0] s_axis_data_tdata  = 'd0;
reg               s_axis_data_tvalid = 1'b0;
reg               s_axis_data_tlast  = 1'b0;  
wire              s_axis_data_tready;

reg               m_axis_data_tready = 1'b1;
wire              m_axis_data_tvalid;
wire              m_axis_data_tlast;
wire signed [31:0] m_axis_data_tdata;

reg		[9:0]	m_cnt = 'd0;

always@(*) begin
	if(cnt == 511) begin
		if(s_axis_data_tready) begin
			s_axis_data_tvalid	<= 1'b1;
			s_axis_data_tlast	<= 1'b1;
			s_axis_data_tdata	<= {16'd0,mem_data_I[cnt]};
		end else begin
			s_axis_data_tvalid	<= 1'b0;
			s_axis_data_tlast	<= 1'b0;			
		end
	end else if(cnt < 511) begin
		if(s_axis_data_tready) begin
			s_axis_data_tvalid	<= 1'b1;
			s_axis_data_tlast	<= 1'b0;
			s_axis_data_tdata	<= {16'd0,mem_data_I[cnt]};
		end else begin
			s_axis_data_tvalid	<= 1'b0;
			s_axis_data_tlast	<= 1'b0;			
		end		
	end else begin
		s_axis_data_tvalid	<= 1'b0;
		s_axis_data_tlast	<= 1'b0;
	end
end



always@(posedge clk250) begin
	if(cnt > 511) begin
		// s_axis_data_tvalid	<= 1'b0;
		// s_axis_data_tlast	<= 1'b0;
		// s_axis_data_tdata	<= 32'd0;
		cnt	<= cnt;
	end else begin
		// if(s_axis_data_tready && s_axis_data_tvalid) begin
		if(s_axis_data_tready) begin
			if(cnt == 511) begin
				cnt	<= cnt + 1'b1;
			// 	s_axis_data_tvalid	<= 1'b1;
			// 	s_axis_data_tlast	<= 1'b1;
			// 	s_axis_data_tdata	<= {16'd0,mem_data_I[cnt]};
			 end else begin
				cnt	<= cnt + 1'b1;
				// s_axis_data_tvalid	<= 1'b1;
				// s_axis_data_tlast	<= 1'b0;
				// s_axis_data_tdata	<= {16'd0,mem_data_I[cnt]};
			end
		end else begin
			cnt	<= cnt;
			// s_axis_data_tdata	<= s_axis_data_tdata;
		end		
	end


	if(m_axis_data_tready && m_axis_data_tvalid) begin
		m_cnt	<= m_cnt + 1'b1;
//		mem_data_O[m_cnt] <= m_axis_data_tdata[31:16];
	   $fwrite(outputfile,"%x\n",m_axis_data_tdata[15:0]);
	   $fwrite(outputfile1,"%x\n",m_axis_data_tdata[31:16]);
	end else begin
		m_cnt	<= m_cnt;
	end
end


xfft_0 fft_ip (
  .aclk(clk250),                                                // input wire aclk
  .aclken(nRst),                                            // input wire aclken
  
  .s_axis_config_tdata({4'd0,20'b00_01_01_01_01_01_01_01_01_01,1'b0,3'd0,5'd9}),                  // input wire [31 : 0] s_axis_config_tdata
//  .s_axis_config_tdata({4'd0,20'b10_10_10_10_10_10_10_10_10_10,1'b0,3'd0,5'd9}),                  // input wire [31 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(1'b1),                // input wire s_axis_config_tvalid
  .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
  
  .event_frame_started(),                  // output wire event_frame_started
  .event_tlast_unexpected(),            // output wire event_tlast_unexpected
  .event_tlast_missing(),                  // output wire event_tlast_missing
  .event_status_channel_halt(),      // output wire event_status_channel_halt
  .event_data_in_channel_halt(),    // output wire event_data_in_channel_halt
  .event_data_out_channel_halt()  // output wire event_data_out_channel_halt
);
endmodule

将IP仿真后的输出数写入到fft_ip_out_im.txt文件中,方便在matlab中作图比较。

4 Matlab仿真

第一步:进入ip产生的cmodel文件夹下,或将xfft_v9_1_bitacc_cmodel_nt64.zip文件解压到自定义的文件夹下,matlab进入该文件夹,刚开始是没有xfft_v9_1_bitacc_mex.mexw64文件的;

第二步:在matlab命令窗口中输入mex -setup -v,查看当前编译器,如果没有找到编译器,需要安装一个vs或MinGW64。我这里使用mingw64编译器,下载链接:TDM-GCC 10.3.0 release | tdm-gcc (jmeubank.github.io)

第三步:命令行窗口输入run make_xfft_v9_1_mex.m,编译成功会产生一个xfft_v9_1_bitacc_mex.mexw64文件

第四步:修改run_xfft_v9_1_mex.m文件

% Generics for this smoke test
generics.C_NFFT_MAX = 9;
generics.C_ARCH = 2;
generics.C_HAS_NFFT = 1;
generics.C_USE_FLT_PT = 0;
generics.C_INPUT_WIDTH = 16; % Must be 32 if C_USE_FLT_PT = 1
generics.C_TWIDDLE_WIDTH = 26; % Must be 24 or 25 if C_USE_FLT_PT = 1
generics.C_HAS_SCALING = 1; % Set to 0 if C_USE_FLT_PT = 1
generics.C_HAS_BFP = 0; % Set to 0 if C_USE_FLT_PT = 1
generics.C_HAS_ROUNDING = 0; % Set to 0 if C_USE_FLT_PT = 1

channels = 1;

samples = 2^generics.C_NFFT_MAX;

X=textread('G:\AvnetWork\Customer\SenardMicro\FFT\matlab\test\fft_ip_in.txt','%s')

data_before_fft = hex2dec(X);
for i=1:1:length(data_before_fft)
    if(data_before_fft(i) > 2^16/2-1)
        data_before_signed(i) = data_before_fft(i) - 2^16;
    else
        data_before_signed(i) = data_before_fft(i);
    end
end
data_before_signed = data_before_signed/(2^16);
% data_before_signed = data_before_signed';


% Handle multichannel FFTs if required
for channel = 1:channels
 
  % Create input data frame: constant data
%   constant_input = 0.5 + 0.5j;
  constant_input = data_before_signed + 0*j;
%   input_raw(1:samples) = constant_input;
%   input_raw(1:samples) = data_before_signed;
    
  if generics.C_USE_FLT_PT == 0
    % Set up quantizer for correct twos's complement, fixed-point format: one sign bit, C_INPUT_WIDTH-1 fractional bits
    % Alas, this function is not available in Octave, but the test values of 0.5+0.5j do not cause quantization errors anyway.
    %    q = quantizer([generics.C_INPUT_WIDTH, generics.C_INPUT_WIDTH-1], 'fixed', 'convergent', 'saturate');
    % Format data for fixed-point input
    %    input = quantize(q,input_raw);
     input = constant_input;
  else
    % Floating point interface - use data directly
    input = constant_input;
  end
  
  % Set point size for this transform
  nfft = generics.C_NFFT_MAX;
  
  % Set up scaling schedule: scaling_sch[1] is the scaling for the first stage
  % Scaling schedule to 1/N: 
  %    2 in each stage for Radix-4/Pipelined, Streaming I/O
  %    1 in each stage for Radix-2/Radix-2 Lite
  if generics.C_ARCH == 1 || generics.C_ARCH == 3
    scaling_sch = ones(1,floor(nfft/2)) * 2;
    if mod(nfft,2) == 1
      scaling_sch = [scaling_sch 1];
    end
  else
    scaling_sch = ones(1,nfft);
  end

  % Set FFT (1) or IFFT (0)
  direction = 1;
      
  if channels > 1
     fprintf('Running the MEX function for channel %d...\n',channel)
  else
     fprintf('Running the MEX function...\n')      
  end
  
  % Run the MEX function
  [output, blkexp, overflow] = xfft_v9_1_bitacc_mex(generics, nfft, input, scaling_sch, direction);
  output = output*2^16;
  o_re = real(output);
  o_im = imag(output);
  fprintf('Running the MEX function...Done\n')     
  
  
Re=textread('G:\AvnetWork\Customer\SenardMicro\FFT\fft_ip_out_re.txt','%s')
data_re = hex2dec(Re);
for i=1:1:length(data_re)
    if(data_re(i) > 2^16/2-1)
        data_re_signed(i) = data_re(i) - 2^16;
    else
        data_re_signed(i) = data_re(i);
    end
end
data_re_signed = data_re_signed;

Im=textread('G:\AvnetWork\Customer\SenardMicro\FFT\fft_ip_out_im.txt','%s')
data_im = hex2dec(Im);
for i=1:1:length(data_im)
    if(data_im(i) > 2^16/2-1)
        data_im_signed(i) = data_im(i) - 2^16;
    else
        data_im_signed(i) = data_im(i);
    end
end
data_im_signed = -data_im_signed; % 这里取负数并没有想明白,只是波形图出来的结果看起来是相反的,请大佬指出。



subplot(2,1,1);
plot(o_re,'r');
hold on;
plot(data_re_signed,'b');
title('real');
subplot(2,1,2);
plot(o_im,'r');
hold on;
plot(data_im_signed,'b');
title('imag');

输出结果:

        红色是cmodel的结果,蓝色是FFT IP输出的结果,这里把实部和虚部分开对比。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值