FFT IP核支持三种数据类型:
1. 定点全精度
1. 定点缩减位宽
1. 块浮点
有四种可选择的FFT运算方式:
1. PipelinedStreaming I/O
1. Radix-4Burst I/O
1. Radix-2Burst I/O
1. Radix-2 Lite Burst I/O
四种方式区别主要体现在运算速度和所占资源上:
本IP核可进行2^M(M=3~16)点的FFT、IFFT,同时支持在线更改变换点数和正负fft的功能。需要注意的是在线变更感换点数功能不支持PipelinedStreaming I/O、Radix-4Burst I/O这两种模式。
同时,IP核支持多数据并行运算,即多个数据流同时进行运算与输出。
下面以配置一个在线可更改变换点数的FFT IP 核为目标,具体说明各个部分。
创建工程、添加IP核,并进行IP核的设置。
第一个选项是同时进行几路数据流并行。
第二个选项是变换的实际点数,需要注意的是我们这里设计可以在线更改变换点数的FFT,所以这里选择的点数是所需要的最大的FFT点数。
下面的五选一选项选择Redix-2 Burst I/O。可以发现当点数小于64时,不支持Radix-4Burst I/O模式。
最后勾选Run Time Configurable Transform Length,这个就是配置可在线更改的FFT IP核。如果不进行勾选,再怎么这传输配置信号也没有作用。
第二页选择整数、不压缩数据、和取整模式。
其他选项如图所示。
第三页同样如图所示。
在配置完成之后可以看到模块的相关信息,比较有用的是latency(延迟)。
总的来说AXI4-Stream总线分为主(一般开头带个m)从(一般开头带个s)两部分组成。一个主连接一个从,形成了一个严密的握手结构。在整个通信过程中,tdata是数据的通路,tready、tvalid两个信号分别由一个主一个从控制,主(或从)准备好接受(或发送)数据时,会拉高自己控制的信号线,如果两边都准备好了(即两个线都拉高了)开始传数据。tlast信号的作用是:当前的数据是一组数据的最后一个时tlast信号会拉高,用于数据对齐,同时还有一定的数据判错作用。还有一个tuser信号,会表明当前周期传递的信号是第几个数据。
event_frame_started:每一新的次fft开始时上跳一次。
event_tlast_unexpected:当s_axis_data_tlast上跳,但IP核认为这并不是最后一个数据时上跳一次。
event_tlast_missing:当IP核认为这是最后一个数据,但s_axis_data_tlast还是低的时候,该信号上跳。
event_fft_overflow:在从数据输出通道输出的数据样本中发现溢出时上跳。只有当overflow选项被选择有效时才出现。
event_data_in_channel_halt:当IP核需要新的输入数据但输入口并没有提供足够的数据时拉高。
event_data_out_channel_halt:当 IP核尝试输出数据但无法输出时(可能时输出对象没有给IP核输出接收使能信号)拉高。只在Non-Realtime 模式下有效。
event_status_channel_halt:当 IP核尝试输出数据到状态通道但无法输出时拉高。只在Non-Realtime 模式下有效。
在设置正确之后,修改变换点数非常简单,只要拉低复位线3个时钟周期以上,之后送入配置命令即可。
可以看到命令长度的低5位就是我们在线更改变换点数的命令位置。
按照官方的命令格式就可以编写自己需要的点数了。
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2018/08/09 11:29:26
// Design Name:
// Module Name: fft_Tes_TB
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module fft_Tes_TB;
reg aclk;
reg aresetn;
reg [15 : 0] s_axis_config_tdata;
reg s_axis_config_tvalid;
wire s_axis_config_tready;
reg [63 : 0] s_axis_data_tdata;
reg s_axis_data_tvalid;
wire s_axis_data_tready;
reg s_axis_data_tlast;
wire [79 : 0] m_axis_data_tdata;
wire [7 : 0] m_axis_data_tuser;
wire m_axis_data_tvalid;
reg m_axis_data_tready;
wire m_axis_data_tlast;
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 [11:0] mem0_re[256:0];
reg [7:0] op_sample= 0;
reg op_sample_first = 1;
reg [7:0] ip_frame=0;
reg [7:0] op_frame=0;
initial $readmemh("C:/Users/74339/Desktop/vivado_code/fft_test/signal.txt",mem0_re);
integer i;
reg s_data;
fft_Tes uut (
.aclk(aclk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.s_axis_config_tdata(s_axis_config_tdata), // 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(s_axis_data_tdata), // input wire [63 : 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 [79 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output wire [7 : 0] m_axis_data_tuser
.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(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
);
always #5 aclk = !aclk;
initial begin
// Initialize Inputs
aclk = 0;
aresetn = 0;
s_axis_config_tvalid = 0;
s_axis_config_tdata = 0;
s_axis_data_tvalid = 0;
s_axis_data_tdata = 0;
s_axis_data_tlast = 0;
m_axis_data_tready = 0;
s_data = 0;
i = 0;
// Wait 100 ns for global reset to finish
#150;
aresetn = 1;
m_axis_data_tready = 1;
s_axis_config_tvalid = 1;
s_axis_config_tdata = 16'b0101100101000100; // FFT desired (and not IFFT
//s_axis_config_tdata = 24'b100100000000000100; // FFT desired (and not IFFT
s_axis_data_tlast = 1;
s_axis_data_tdata = 96'h000000;
s_axis_data_tvalid = 0;
#3000;
aresetn = 0;
#300;
aresetn = 1;
m_axis_data_tready = 1;
s_axis_config_tvalid = 1;
s_axis_config_tdata = 16'b0101100101000110; // FFT desired (and not IFFT
//s_axis_config_tdata = 24'b100100000000000111; // FFT desired (and not IFFT
s_axis_data_tlast = 1;
s_axis_data_tdata = 96'h000000;
s_axis_data_tvalid = 0;
s_axis_data_tvalid = 0;
end
always @(posedge aclk)
begin
if(s_axis_data_tready == 1)
begin
s_axis_data_tvalid <= 1;
//s_axis_data_tdata <= s_data;
//s_data = s_data +1;
s_axis_data_tdata <= mem0_re[i];
$display("mem_a[%d] = %h", i, mem0_re[i]);
if((i % 16)==0)
s_axis_data_tlast <= 1;
else
s_axis_data_tlast <= 0;
i = i + 1;
end
end
endmodule