基於FPGA的FFT算法實現(2)

項目簡述

前面我們已經講解過Xilinx中FFT IP的使用,但是使用的時候IP的配置接口我們沒有進行相應的講解,直接使用GUI配置好的接口,這在現實應用中很不方方便,會讓人感覺到還不如自己手寫一個FFT算法,當然博主也可完全手撕FFT、CORDIC代碼,但是把IP用好了絕對比我們手寫的代碼要好用的多。這篇博客主要講解FFT IP的重配置及其參數的意義,最後將給出Modelsim與MATLAB的兩盒驗證。

本次實驗所使用的軟硬件環境如下:
1、VIVADO 2019.1
2、Modelsim 10.7
3、MATLAB 2015b

這裏再多說一句,從博主之前的文章中可以發現MATLAB在信號處理中的正確性,所以絕對不要說MATLAB不重要。而且一般Xilinx的IP核都可以生成相應的m文件,也就是說我們可以實現MATLAB與Modelsim完全一致的驗證。 所以要想做信號處理或算法得FPGA實現一定要掌握MATLAB。

FFT進行重配置

我們在定製FFT IP核得時候就已經對FFT進行了配置,但是我們實際使用IP得時候經常可以碰見IP得重配置,這一塊內容直至一年前我進行PLL得重配置得時候還是無從下手,但是這篇文章我們主要講解FFT IP得重配置,可以讓大家學習到Xilinx IP重配置得設計技巧。這裏我們首先強調技術手冊得重要性,因爲市面上沒有這方面得資料,所以我們要學習相應IP得重配置必須學習技術手冊。我們首先看FFT IP得技術手冊如下:
在這裏插入圖片描述
總共不到100頁,是值得瀏覽一遍的,因爲其他得IP基本上也是這幾部分。C Model我們上篇博客已經進行了介紹,主要是爲了我們在MATLAB中驗證該模塊得正確性來使用的。

首先我們來看FFT IP核的接口引腳:
在這裏插入圖片描述
其中FFT的接口主要可以分爲6組如上圖:
1、FFT的重配置接口
2、FFT的數據輸入接口,遵循AXI-Stream協議
3、FFT的時鐘、時鐘使能、復位信號(注意復位信號要多給幾個時鐘)
4、FFT的數據輸出接口,遵循AXI-Stream協議
5、可以輸出FFT IP的當前的狀態(一般不常使用)
6、可以輸出一些FFT的錯誤信息,比如輸入的last未知不正確或沒有,數據溢出等等
在這裏插入圖片描述
在這裏插入圖片描述
上面是簡要介紹了FFT IP的接口描述。具體的功能引腳的定義還是需要我們查找技術手冊,我們這篇博客主要講解IP的重配置,不會對AXI-Stream進行過多的介紹。

從FFT IP技術手冊的首頁我們可以發現,FFT可以完成的功能:
在這裏插入圖片描述
上面也是我們進行重配置的主要內容:
1、FFT最大變換的點數
2、FFT正變換還是逆變換
3、每級蝶形運算縮放因子的輸入
4、CP_LEN的長度(這個具體的所用,我也不知道,知道的同學可以在評論裏討論一下)

要想配置上面的這些信息,我們就一定要進行配置數據的輸入,配置數據的不同位數代表不同的功能,如下:
在這裏插入圖片描述
上面爲什麼會有PAD,主要是因爲字節對齊,每個配置功能佔整數個字節。其中除了SCALE_SCH上面的位寬都是確定的,如下:
在這裏插入圖片描述
上面每位的取值情況如下:
在這裏插入圖片描述
在這裏插入圖片描述
上面的功能需要大家仔細讀,尤其是SCALE_SCH,這裏我給大家稍微解讀一下。
1、每兩個比特位構成的數字作爲一級蝶形運算的縮放比例。2位比特位構成了0,1,2,3,這三個數代表分別代表蝶形運算之後的結果移位的個數。
2、SCALE_SCH的位數對於基-4 FFT算法是2ceil(NFFT2)2*ceil(\frac{NFFT}{2}),其中ceil是指向上取整;對於基-2 FFT算法是2NFFT2*NFFT,相信熟悉FFT蝶形運算的同學很容易明白,其實這就是蝶形運算的個數然後乘以2。
關於FFT重配置的理論我們就講到這裏,下面我們給出相應的代碼供大家學習,並且將代碼與上篇博客中的MATLAB生成的結果相互驗證,從而使得MATLAB與VIVADO實現雙重驗證。

FPGA代碼

FPGA邏輯代碼

tx_ifft_op模塊:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : tx_ifft_op.v
// Create Time  : 2020-06-04 16:33:48
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module tx_ifft_op(
	input             		sclk 					,
	input             		rst_n					,
	input             		cfg_vld					,
	output	reg       		p1_start 				,
	input             		s_config_tvalid			,
	input 		[29:0]	  	s_config_tdata			,
	input 			  		s_data_tvalid 			,
	input 		[23:0]      s_data_tdata			,	
	input             		s_data_tlast			,		
	output reg        		s_axis_config_tready	,
	output reg        		s_axis_data_tready		,
	output reg 	[31:0] 		m_axis_data_tdata  		,
	output     	[23:0] 		m_axis_data_tuser  		,
	output reg        		m_axis_data_tvalid		,
	input             		m_axis_data_tready		,	
	output reg        		m_axis_data_tlast		,
	output  	[ 7:0]   	m_axis_status_tdata		,
	output            		m_axis_status_tvalid	,
	input             		m_axis_status_tready	,
	output            		event_frame_started		,
	output            		event_tlast_unexpected	,
	output            		event_tlast_missing		,
	output            		event_fft_overflow		,
	output            		event_status_channel_halt	,
	output            		event_data_in_channel_halt	,
	output            		event_data_out_channel_halt	,
	output  	[ 9:0]     	NOFDM
);

//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/            
reg 			[ 9:0]		NOFDM_CNT				;
wire 			[39:0] 		s_axis_config_tdata 	;
wire 						s_axis_config_tvalid	;
wire 			[31:0]   	s_axis_data_tdata		;
wire            			s_axis_data_tvalid		;
wire            			s_axis_data_tlast		;   
wire 			[ 4:0]      NFFT					;
wire 			[13:0]     	SCALE_SCH				;
wire 			[11:0]     	RE_DATA					;
wire 			[11:0]     	IM_DATA					;
wire            			DATA_LAST				;
wire            			DATA_EN					;
wire            			FWD_INV					;
wire            			fft_config_en			;
wire 			[31:0]   	m_axis_data_tdata_store	;
wire            			m_axis_data_tvalid_store;
wire            			m_axis_data_tlast_store	;
reg             			p1_start_D				;
wire 			[12:0]     	CP_LEN					;
reg 						last_delay				;
wire 						Neg_ifft_tlast			;
reg 			[ 4:0]		rstn_cnt				;
wire 						s_axis_data_tready1 	;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign 	Neg_ifft_tlast		=		last_delay&&(~m_axis_data_tlast_store);

always@(posedge sclk)
	last_delay 			<=   		m_axis_data_tlast_store;

always @(posedge sclk)
	if(rst_n == 1'b0)
		NOFDM_CNT 		<=   		10'd0;
	else if(NOFDM_CNT == NOFDM+1'b1 && NOFDM != 10'd0)
		NOFDM_CNT 		<=   		10'd0;
	else if(Neg_ifft_tlast == 1'b1)
		NOFDM_CNT 		<=   		NOFDM_CNT + 1'b1;		

always @(posedge sclk)
    if(rst_n == 1'b0)
        rstn_cnt 		<=   		5'h1f;  
	else if(cfg_vld == 1'b1)
		rstn_cnt 		<=   		5'd0;
	else if(rstn_cnt == 5'h1f)
		rstn_cnt 		<=    		rstn_cnt;
	else 
		rstn_cnt  		<=   		rstn_cnt + 1'b1;

always @(posedge sclk)
	if(rst_n == 1'b0)
		p1_start 		<=   		1'b0;
	else if(rstn_cnt == 5'h1e)
		p1_start 		<=    		1'b1;
	else if(NOFDM_CNT == NOFDM+1'b1 && NOFDM != 10'd0)
		p1_start 		<=   		1'b1;
	else 
		p1_start 		<=   		1'b0;


always @(posedge sclk)
	if(rst_n == 1'b0)
		s_axis_data_tready 	<=   	1'b1;
	else if(Neg_ifft_tlast == 1'b1)
		s_axis_data_tready 	<=   	1'b1;    
	else if(s_data_tlast == 1'b1)
		s_axis_data_tready 	<=   	1'b0;
		

always @(posedge sclk)
	p1_start_D 			<=   		p1_start;

always @(posedge sclk)
	if(rst_n == 1'b0)
		s_axis_config_tready 	<=   1'b0;
	else if(p1_start_D == 1'b1)
		s_axis_config_tready 	<=   1'b0;
	else if(Neg_ifft_tlast == 1'b1)
		s_axis_config_tready 	<=   1'b1;

always @(posedge sclk)
begin
	m_axis_data_tdata  	<=   		m_axis_data_tdata_store;
	m_axis_data_tvalid 	<=   		m_axis_data_tvalid_store && m_axis_data_tready;
	m_axis_data_tlast  	<=   		m_axis_data_tlast_store;
end 


ifft_op_map ifft_op_map
(
	.sclk 						(sclk 						),
	.rst_n						(rst_n						),
	.s_config_tvalid			(s_config_tvalid			),
	.s_config_tdata 			(s_config_tdata 			),
	.s_data_tvalid  			(s_data_tvalid  			),
	.s_data_tdata   			(s_data_tdata   			),
	.s_data_tlast   			(s_data_tlast   			),
	.RE_DATA        			(RE_DATA        			),
	.IM_DATA        			(IM_DATA        			),
	.DATA_EN        			(DATA_EN        			),
	.DATA_LAST      			(DATA_LAST      			),
	.fft_config_en  			(fft_config_en  			),
	.NFFT						(NFFT						),
	.CP_LEN						(CP_LEN						),
	.SCALE_SCH					(SCALE_SCH					),
	.FWD_INV					(FWD_INV					),
	.NOFDM						(NOFDM						) 
	
);
/*===================================================================
====================================================================*/	
fft_sig_comp fft_sig_comp
(
	.sclk	         		  	(sclk	         		  	),
	.rst_n         		      	(rst_n         		      	),
	.P1_EN        		      	(DATA_EN                    ),
	.RE_P1_DATA   		      	(RE_DATA   	              	),
	.IM_P1_DATA   		      	(IM_DATA   	              	),
	.data_LAST    		      	(DATA_LAST    	          	),
	.fft_config_en		      	(fft_config_en		      	),
	.NFFT         		      	(NFFT         		      	),
	.CP_LEN		 		      	(CP_LEN		 		      	),
	.SCALE_SCH	 		      	(SCALE_SCH	 		      	),
	.FWD_INV		 		  	(FWD_INV		 		  	),
	.s_axis_config_tdata      	(s_axis_config_tdata        ),
	.s_axis_config_tvalid     	(s_axis_config_tvalid  		),
	.s_axis_data_tdata        	(s_axis_data_tdata          ),
	.s_axis_data_tvalid       	(s_axis_data_tvalid         ),
	.s_axis_data_tlast        	(s_axis_data_tlast          ) 
	                                   
);


tx_xfft_0 tx_xfft_0 (
  .aclk							(sclk						),   
  .aresetn						(rst_n						),   
  .s_axis_config_tdata			(s_axis_config_tdata		),   
  .s_axis_config_tvalid			(s_axis_config_tvalid		),   
  .s_axis_config_tready			(sim_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_tready1 		),   
  .s_axis_data_tlast 			(s_axis_data_tlast			),   
  
  .m_axis_data_tdata			(m_axis_data_tdata_store	),   
  .m_axis_data_tuser			(m_axis_data_tuser			),   
  .m_axis_data_tvalid			(m_axis_data_tvalid_store	),   
  .m_axis_data_tready			(m_axis_data_tready			),   
  .m_axis_data_tlast			(m_axis_data_tlast_store	),   
  .m_axis_status_tdata			(m_axis_status_tdata		),   
  
  .m_axis_status_tvalid		  	(m_axis_status_tvalid		),
  .m_axis_status_tready		  	(m_axis_status_tready		),
  .event_frame_started		  	(event_frame_started		),
  .event_tlast_unexpected	  	(event_tlast_unexpected		),
  .event_tlast_missing		  	(event_tlast_missing		),
  .event_fft_overflow		  	(event_fft_overflow			),
  .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) 
);



endmodule 

ifft_op_map模塊:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : ifft_op_map.v
// Create Time  : 2020-06-04 16:49:13
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module ifft_op_map
(
	input 				sclk			,
	input 				rst_n			,
	input 				s_config_tvalid	,
	input 		[29:0]	s_config_tdata	,	
	input 				s_data_tvalid	,
	input 		[23:0]	s_data_tdata	,
	input 				s_data_tlast	,	
	output	reg [11:0]	RE_DATA			,
	output	reg [11:0]	IM_DATA			,
	output	reg 		DATA_EN			,
	output	reg 		DATA_LAST 		,	
	output	reg 		fft_config_en 	,
	output	reg [ 4:0] 	NFFT 			,
	output	reg [12:0] 	CP_LEN 			,
	output	reg [13:0] 	SCALE_SCH 		,
	output	reg 		FWD_INV 		,
	output	reg [ 9:0]	NOFDM
	
);
/*===================================================================
====================================================================*/
wire 			[ 1:0]	fft_mode 		;
wire 			[ 9:0]	nofdm 			;
wire 			[ 2:0]	cp_pro 			;
wire 			[13:0]	scale 			;
wire      				inv 			;

reg  			[ 2:0]  PRO 			; 
reg  			[ 1:0]  MODE			;
reg  			[ 1:0]  MODE1			;
reg  			[ 9:0]  NOFDM1			;
reg  			[ 2:0]  PRO1			; 
reg  			[13:0]  SCALE_SCH1		;
reg  			        FWD_INV1		;
reg  			        fft_config_en1	;		

assign  	fft_mode	 	=  		s_config_tdata[1:0];
assign  	nofdm   	 	=  		s_config_tdata[11:2];
assign  	cp_pro  	 	=  		s_config_tdata[14:12];
assign  	scale   	 	=  		s_config_tdata[28:15];
assign  	inv     	 	=  		s_config_tdata[29];

always @(posedge sclk)
begin
	if(rst_n == 1'b0)begin
	    MODE1		   		<=   	2'b00;
		NOFDM1		   		<=   	10'd0;
		PRO1		   		<=   	3'b000; 
		SCALE_SCH1      	<=   	14'd0;
		FWD_INV1        	<=   	1'b0;

	end else if(s_config_tvalid)begin		
	    MODE1		   		<=   	fft_mode;
		NOFDM1         		<=   	nofdm;
		PRO1		   		<=   	cp_pro; 
		SCALE_SCH1     		<=   	scale;
		FWD_INV1       		<=   	inv;
	end 
end 

always@(posedge sclk)begin
        MODE		   		<=   	MODE1;
	    NOFDM          		<=   	NOFDM1;
		PRO		       		<=   	PRO1; 
		SCALE_SCH      		<=  	SCALE_SCH1;
		FWD_INV        		<=  	FWD_INV1;
end
 
always @(posedge sclk)begin
		RE_DATA 	   		<=   	s_data_tdata[23:12];
		IM_DATA 	   		<=   	s_data_tdata[11:0]; 
		DATA_EN 	   		<=   	s_data_tvalid;
		DATA_LAST 	   		<=   	s_data_tlast;
end 

always@(posedge sclk)
begin   
      fft_config_en1  		<=   	s_config_tvalid;
	  fft_config_en   		<=   	fft_config_en1;
end	  

always @(posedge sclk)
	if(PRO1 == 3'd0)
		CP_LEN 				<=  	13'd0;
	else if(PRO1 == 3'd1)//1/32	
		CP_LEN				<=  	13'd32;
	else if(PRO1 == 3'd2)//1/16	
		CP_LEN				<=  	13'd64;
	else if(PRO1 == 3'd3)//1/8;	
		CP_LEN				<=  	13'd128;
	else if(PRO1 == 3'd4)//1/4;	
		CP_LEN				<=  	13'd256;
	else 	
		CP_LEN				<=  	13'd0;	

always @(posedge sclk)
	case(MODE1)
		2'b00:	NFFT		<=  	5'b01010;//1k
		2'b01:	NFFT		<=  	5'b01011;//2k
		2'b10:	NFFT		<=  	5'b01100;//4k
		2'b11:	NFFT		<=  	5'b01101;//8k
		default:NFFT 		<=  	5'b00000;
	endcase 

endmodule

fft_sig_comp模塊:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : fft_sig_comp.v
// Create Time  : 2020-06-04 16:55:01
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module fft_sig_comp(
	input 				sclk 				,
	input 				rst_n				,
	input 				P1_EN				,
	input 		[11:0]	RE_P1_DATA			,
	input 		[11:0]	IM_P1_DATA			,
	input 				data_LAST			,
	input 				fft_config_en		,
	input 		[ 4:0] 	NFFT 				,
	input 		[12:0] 	CP_LEN 				,
	input 		[13:0] 	SCALE_SCH 			,
	input 				FWD_INV 			,
	output  	[39:0] 	s_axis_config_tdata	,
	output  			s_axis_config_tvalid,
	output  	[31:0] 	s_axis_data_tdata  	,
	output  			s_axis_data_tvalid  ,
	output  			s_axis_data_tlast           
	                                   
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/

reg 			[39:0] 	s_axis_config_tdata_reg	;
reg 					s_axis_config_tvalid_reg;                            
reg 			[31:0] 	s_axis_data_tdata_reg  	;
reg 					s_axis_data_tvalid_reg  ;
reg 					s_axis_data_tlast_reg   ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
assign 	s_axis_config_tdata  	= 	s_axis_config_tdata_reg;
assign 	s_axis_config_tvalid 	= 	s_axis_config_tvalid_reg;
assign 	s_axis_data_tdata    	= 	s_axis_data_tdata_reg;
assign 	s_axis_data_tvalid   	= 	s_axis_data_tvalid_reg;
assign 	s_axis_data_tlast    	= 	s_axis_data_tlast_reg;


always @(posedge sclk)
	s_axis_config_tdata_reg 	<=  {1'b0,SCALE_SCH,FWD_INV,3'b000,CP_LEN,3'b000,NFFT};

always @(posedge sclk)
	s_axis_config_tvalid_reg 	<=  fft_config_en;

always @(posedge sclk)
	s_axis_data_tdata_reg 		<=  {4'b0000,IM_P1_DATA,4'b0000,RE_P1_DATA};

always @(posedge sclk)
	s_axis_data_tvalid_reg 		<=  P1_EN;

always @(posedge sclk)
	s_axis_data_tlast_reg 		<=  data_LAST;


endmodule

上面的代碼聯繫之前的理論部分,便可以學會FFT的重配置,包括經過這篇博客的學習要學會其他Xilinx常用IP的重配置,比如:DDS、FIR等等。

FPGA測試代碼

tb_tx_ifft_op模塊:

`timescale 1ns / 1ps


module tb_tx_ifft_op;

reg         sclk                    ;
reg         rst_n                   ;
    
reg         cfg_vld                 ;
        
reg         s_config_tvalid         ;
reg [29:0]  s_config_tdata          ;
reg         s_data_tvalid;
reg         s_data_tvalid_delay,s_data_tvalid_delay1;
reg [23:0]  s_data_tdata; 

reg         s_data_tlast;
reg         m_axis_data_tready         ;
reg         m_axis_status_tready       ;

wire       s_axis_config_tready        ;
wire       s_axis_data_tready          ;
wire [31:0]m_axis_data_tdata           ;
wire [23:0]m_axis_data_tuser           ;
wire       m_axis_data_tvalid          ;
wire       m_axis_data_tlast           ;
wire [7:0] m_axis_status_tdata         ;
wire       m_axis_status_tvalid        ;
wire       event_frame_started         ;
wire       event_tlast_unexpected      ;
wire       event_tlast_missing         ;
wire       event_fft_overflow          ;
wire       event_status_channel_halt   ;
wire       event_data_in_channel_halt  ;
wire       event_data_out_channel_halt ; 
wire [9:0] NOFDM                       ;
wire       p1_start                    ;

reg  [1:0] fft_mode                    ;
reg  [9:0] nofdm                       ;
reg  [2:0] cp_pro                      ;
reg  [13:0]scale                       ;
reg        inv                         ;

reg  [11:0]re_data                     ;
reg  [11:0]im_data                     ;
    


always @(posedge sclk)
begin
    s_data_tvalid_delay  <=  s_data_tvalid;
    s_data_tvalid_delay1 <=  s_data_tvalid_delay;
end

initial
begin
    #0;
    sclk =1'b0;
    rst_n=1'b0;
    cfg_vld = 1'b0;
    m_axis_data_tready = 1'b1;
    m_axis_status_tready = 1'b1;
    s_config_tvalid = 1'b0;
    s_config_tdata = 30'd0;


    fft_mode=2'b01;
    nofdm = 10'd1;
    cp_pro = 3'b000;
    scale = 14'b01_0110_1010_1010;
    //scale = 14'd0;
    inv = 1'b0; 

    s_data_tvalid = 1'b0;
    s_data_tlast = 1'b0;

    repeat(1) @(posedge sclk)#1;
    cfg_vld = 1'b1;
    repeat(1) @(posedge sclk)#1;
    cfg_vld = 1'b0;
    repeat(30) @(posedge sclk)#1;
    rst_n =1'b1;
    repeat(30) @(posedge sclk)#1;
    s_config_tvalid = 1'b1;
    s_config_tdata = {inv,scale,cp_pro,nofdm,fft_mode};
    repeat(1) @(posedge sclk)#1;
    s_config_tvalid = 1'b0;
    repeat(300) @(posedge sclk)#1;
    s_data_tvalid = 1'b1;
    s_data_tlast = 1'b0;
    repeat(1) @(posedge sclk)#1;
    s_config_tvalid = 1'b0;
    repeat(2047) @(posedge sclk)#1;
    s_data_tlast = 1'b0;
    s_data_tvalid = 1'b0;//mark for test
    repeat(1) @(posedge sclk)#1;
    s_data_tlast = 1'b1;
    repeat(1) @(posedge sclk)#1;
    s_data_tlast = 1'b0;
end
always #10 sclk = ~sclk;

//=========================================================================
//   input
//========================================================================= 
    integer fid1;
    integer fid2;
    initial  
    begin
        fid2 = $fopen("IM_DATA.txt","r");
        fid1 = $fopen("RE_DATA.txt","r");
    end

    always@(posedge sclk)
    begin
        if(s_data_tvalid)begin
            $fscanf(fid1,"%d",re_data);
            $fscanf(fid2,"%d",im_data); 
        end    
    end
 
    always @(posedge sclk)
    begin
        s_data_tdata <=  {re_data,im_data}; 
    end 
//=========================================================================
// output
//========================================================================= 
wire signed [11:0] re_out;
wire signed [11:0] im_out;

assign re_out = {m_axis_data_tdata[15],m_axis_data_tdata[10:0]};    
assign im_out = {m_axis_data_tdata[31],m_axis_data_tdata[26:16]};   
    
    integer fid3;
    initial 
    begin
        fid3 = $fopen("re_fft_data.txt","w");
    end
    
    always@(posedge sclk)
    begin
        if(m_axis_data_tvalid)
            $fwrite(fid3,"%d\n",re_out);
    end

    integer fid4;
    initial 
    begin
        fid4 = $fopen("im_fft_data.txt","w");
    end
    
    always@(posedge sclk)
    begin
        if(m_axis_data_tvalid)
            $fwrite(fid4,"%d\n",im_out);
    end

tx_ifft_op uut
(
    .sclk                       (sclk                       ),
    .rst_n                      (rst_n                      ),
    .cfg_vld                    (cfg_vld                    ),
    .p1_start                   (p1_start                   ),
    .s_config_tvalid            (s_config_tvalid            ),
    .s_config_tdata             (s_config_tdata             ),
    .s_data_tvalid              (s_data_tvalid_delay1       ),
    .s_data_tdata               (s_data_tdata               ),  
    .s_data_tlast               (s_data_tlast               ),
    .m_axis_data_tready         (m_axis_data_tready         ),
    .m_axis_status_tready       (m_axis_status_tready       ),
    .s_axis_config_tready       (s_axis_config_tready       ), 
    .s_axis_data_tready         (s_axis_data_tready         ), 
    .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_tlast          (m_axis_data_tlast          ),
    .m_axis_status_tdata        (m_axis_status_tdata        ),
    .m_axis_status_tvalid       (m_axis_status_tvalid       ),
    .event_frame_started        (event_frame_started        ),
    .event_tlast_unexpected     (event_tlast_unexpected     ),
    .event_tlast_missing        (event_tlast_missing        ),
    .event_fft_overflow         (event_fft_overflow         ),
    .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),
    .NOFDM                      (NOFDM                      )   
);

endmodule

MATLAB驗證

有關MATLAB對FFT IP核調用的部分,我們上篇博客已經進行了詳細的講解,在這裏我們將給出MATLAB與Modelsim生成的數據相對比的代碼:

clc;
clear all;
load fft_data_com.mat
sim_options = struct(...
    'MODE',        '2k'   ...         %fft模式  1k 2k 4k 8k
    );
tx_nFrame=1;
%------------------------------------------------------------------------------
% Parameters Definition
%------------------------------------------------------------------------------
switch sim_options.MODE
    case '1k'
        NFFT   = 1024;       % FFT number of points
    case '2k'
        NFFT   = 2048;       % FFT number of points
    case '4k'
        NFFT   = 4096;       % FFT number of points
    case '8k'
        NFFT   = 8192;       % FFT number of points
    otherwise, error('sim_options UNKNOWN MODE');
end
fid1 = fopen('re_fft_data.txt','r');
real_data_sim = fscanf(fid1,'%d');

fid1 = fopen('im_fft_data.txt','r');
imag_data_sim = fscanf(fid1,'%d');

start_Idx = NFFT*(tx_nFrame - 1);
if(isempty(real_data_sim))
    real_data_result = 0;
    imag_data_result = 0;
else
    real_data_result = sum(abs(real(fft_data_com(start_Idx+1:start_Idx+NFFT)) - real_data_sim(start_Idx+1:start_Idx+NFFT)));
    imag_data_result = sum(abs(imag(fft_data_com(start_Idx+1:start_Idx+NFFT)) - imag_data_sim(start_Idx+1:start_Idx+NFFT)));
end
a = real_data_result + imag_data_result

運行結果如下:
在這裏插入圖片描述
從上面結果可以驗證我們實驗的正確性,從而說明MATLAB與VIVADO輸出的數據完全相同,兩者相互驗證了實驗的正確性。

參考文獻

[1]、電子發燒友學院

總結

創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。或者對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章