基于FPGA的FFT算法实现

项目简述

前面我们已经讲解过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算法是

     2 
    
   
     ∗ 
    
   
     c 
    
   
     e 
    
   
     i 
    
   
     l 
    
   
     ( 
    
    
     
     
       N 
      
     
       F 
      
     
       F 
      
     
       T 
      
     
    
      2 
     
    
   
     ) 
    
   
  
    2*ceil(\frac{NFFT}{2}) 
   
  
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.64444em; vertical-align: 0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right: 0.222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.222222em;"></span></span><span class="base"><span class="strut" style="height: 1.21733em; vertical-align: -0.345em;"></span><span class="mord mathdefault">c</span><span class="mord mathdefault">e</span><span class="mord mathdefault">i</span><span class="mord mathdefault" style="margin-right: 0.01968em;">l</span><span class="mopen">(</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.872331em;"><span class="" style="top: -2.655em;"><span class="pstrut" style="height: 3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span class="" style="top: -3.23em;"><span class="pstrut" style="height: 3em;"></span><span class="frac-line" style="border-bottom-width: 0.04em;"></span></span><span class="" style="top: -3.394em;"><span class="pstrut" style="height: 3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right: 0.10903em;">N</span><span class="mord mathdefault mtight" style="margin-right: 0.13889em;">F</span><span class="mord mathdefault mtight" style="margin-right: 0.13889em;">F</span><span class="mord mathdefault mtight" style="margin-right: 0.13889em;">T</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height: 0.345em;"><span class=""></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">)</span></span></span></span></span>,其中ceil是指向上取整;对于基-2 FFT算法是<span class="katex--inline"><span class="katex"><span class="katex-mathml"> 
 
  
   
   
     2 
    
   
     ∗ 
    
   
     N 
    
   
     F 
    
   
     F 
    
   
     T 
    
   
  
    2*NFFT 
   
  
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.64444em; vertical-align: 0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right: 0.222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.222222em;"></span></span><span class="base"><span class="strut" style="height: 0.68333em; vertical-align: 0em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mord mathdefault" style="margin-right: 0.13889em;">F</span><span class="mord mathdefault" style="margin-right: 0.13889em;">F</span><span class="mord mathdefault" style="margin-right: 0.13889em;">T</span></span></span></span></span>,相信熟悉FFT蝶形运算的同学很容易明白,其实这就是蝶形运算的个数然后乘以2。<br> 关于FFT重配置的理论我们就讲到这里,下面我们给出相应的代码供大家学习,并且将代码与上篇博客中的MATLAB生成的结果相互验证,从而使得MATLAB与VIVADO实现双重验证。</p> 

FPGA代码

FPGA逻辑代码

tx_ifft_op模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// 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
);

//</span>
//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 ;

//</span>
//************** 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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218

ifft_op_map模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// 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 <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>s_config_tvalid<span class="token punctuation">)</span>begin		
    MODE1		   		<span class="token operator">&lt;=</span>   	fft_mode<span class="token punctuation">;</span>
	NOFDM1         		<span class="token operator">&lt;=</span>   	nofdm<span class="token punctuation">;</span>
	PRO1		   		<span class="token operator">&lt;=</span>   	cp_pro<span class="token punctuation">;</span> 
	SCALE_SCH1     		<span class="token operator">&lt;=</span>   	scale<span class="token punctuation">;</span>
	FWD_INV1       		<span class="token operator">&lt;=</span>   	inv<span class="token punctuation">;</span>
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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126

fft_sig_comp模块:

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : nnzhang1996@foxmail.com
// 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

);

//</span>
//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 ;

//</span>
//************** 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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

上面的代码联系之前的理论部分,便可以学会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<span class="token operator">=</span><span class="token number">2</span>'b01<span class="token punctuation">;</span>
nofdm <span class="token operator">=</span> <span class="token number">10</span>'d1<span class="token punctuation">;</span>
cp_pro <span class="token operator">=</span> <span class="token number">3</span>'b000<span class="token punctuation">;</span>
scale <span class="token operator">=</span> <span class="token number">14</span>'b01_0110_1010_1010<span class="token punctuation">;</span>
<span class="token comment">//scale = 14'd0;</span>
inv <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span> 

s_data_tvalid <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>
s_data_tlast <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>

<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
cfg_vld <span class="token operator">=</span> <span class="token number">1</span>'b1<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
cfg_vld <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
rst_n <span class="token operator">=</span><span class="token number">1</span>'b1<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_config_tvalid <span class="token operator">=</span> <span class="token number">1</span>'b1<span class="token punctuation">;</span>
s_config_tdata <span class="token operator">=</span> <span class="token punctuation">{<!-- --></span>inv<span class="token punctuation">,</span>scale<span class="token punctuation">,</span>cp_pro<span class="token punctuation">,</span>nofdm<span class="token punctuation">,</span>fft_mode<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_config_tvalid <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_data_tvalid <span class="token operator">=</span> <span class="token number">1</span>'b1<span class="token punctuation">;</span>
s_data_tlast <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_config_tvalid <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">2047</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_data_tlast <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>
s_data_tvalid <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span><span class="token comment">//mark for test</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_data_tlast <span class="token operator">=</span> <span class="token number">1</span>'b1<span class="token punctuation">;</span>
<span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>#<span class="token number">1</span><span class="token punctuation">;</span>
s_data_tlast <span class="token operator">=</span> <span class="token number">1</span>'b0<span class="token punctuation">;</span>

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@<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>
begin
    <span class="token keyword">if</span><span class="token punctuation">(</span>s_data_tvalid<span class="token punctuation">)</span>begin
        $<span class="token function">fscanf</span><span class="token punctuation">(</span>fid1<span class="token punctuation">,</span><span class="token string">"%d"</span><span class="token punctuation">,</span>re_data<span class="token punctuation">)</span><span class="token punctuation">;</span>
        $<span class="token function">fscanf</span><span class="token punctuation">(</span>fid2<span class="token punctuation">,</span><span class="token string">"%d"</span><span class="token punctuation">,</span>im_data<span class="token punctuation">)</span><span class="token punctuation">;</span> 
    end    
end

always @<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>
begin
    s_data_tdata <span class="token operator">&lt;=</span>  <span class="token punctuation">{<!-- --></span>re_data<span class="token punctuation">,</span>im_data<span class="token punctuation">}</span><span class="token punctuation">;</span> 
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<span class="token punctuation">;</span>
initial 
begin
    fid3 <span class="token operator">=</span> $<span class="token function">fopen</span><span class="token punctuation">(</span><span class="token string">"re_fft_data.txt"</span><span class="token punctuation">,</span><span class="token string">"w"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
end

always@<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>
begin
    <span class="token keyword">if</span><span class="token punctuation">(</span>m_axis_data_tvalid<span class="token punctuation">)</span>
        $<span class="token function">fwrite</span><span class="token punctuation">(</span>fid3<span class="token punctuation">,</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span>re_out<span class="token punctuation">)</span><span class="token punctuation">;</span>
end

integer fid4<span class="token punctuation">;</span>
initial 
begin
    fid4 <span class="token operator">=</span> $<span class="token function">fopen</span><span class="token punctuation">(</span><span class="token string">"im_fft_data.txt"</span><span class="token punctuation">,</span><span class="token string">"w"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
end

always@<span class="token punctuation">(</span>posedge sclk<span class="token punctuation">)</span>
begin
    <span class="token keyword">if</span><span class="token punctuation">(</span>m_axis_data_tvalid<span class="token punctuation">)</span>
        $<span class="token function">fwrite</span><span class="token punctuation">(</span>fid4<span class="token punctuation">,</span><span class="token string">"%d\n"</span><span class="token punctuation">,</span>im_out<span class="token punctuation">)</span><span class="token punctuation">;</span>
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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

运行结果如下:
在这里插入图片描述
从上面结果可以验证我们实验的正确性,从而说明MATLAB与VIVADO输出的数据完全相同,两者相互验证了实验的正确性。

参考文献

[1]、电子发烧友学院

总结

创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。为行业贡献及其微小的一部分。或者对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值