项目简述
前面我们已经讲解过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}) 2∗ceil(2NFFT),其中ceil是指向上取整;对于基-2 FFT算法是 2 ∗ N F F T 2*NFFT 2∗NFFT,相信熟悉FFT蝶形运算的同学很容易明白,其实这就是蝶形运算的个数然后乘以2。
关于FFT重配置的理论我们就讲到这里,下面我们给出相应的代码供大家学习,并且将代码与上篇博客中的MATLAB生成的结果相互验证,从而使得MATLAB与VIVADO实现双重验证。
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
);
//========================================================================================\
//**************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