挺多人问我原工程,我就把它打包放网盘了,需要自取。
链接:https://pan.baidu.com/s/1nDqoB2a1y-TZJhI3lfHXtQ
提取码:tm26
———————————————————————以下原文————————————————————————————
1.FFT IP核无法进行8/16/32点的配置,意味着最少从64点起步。我不知道是不是版本的问题,反正我和我同学的都是这样,脑阔疼。 我是2016.3的vivado版本。
切记,RESET一定要勾选,一定要,一定要!话说三遍,你不勾选自己去看后果吧,上电复位最少三个时钟切记。 关于这个XK_INDEX的话,这个会使得你在后续FFT处理中非常的方便。
3.关于s_axis_config_tdata,这个是FFT的配置数据,形式在FFT IP Core说明书中是有的,只不过看的有点脑阔疼。告诉你个小窍门
看到了吗,在这个页面下,关于配置数据的格式是有定义的 ,你根据你的定义去进行修改即可。
4.关于某时刻你发现输入的数据一切完好,但是输出却是XXXXXXX,mmp,很烦了。
这是因为你FFT例化的问题,例化的时候一定要例化好,把原生的文件原生的端口一个不落的加进来
fft fft_module (
.aclk(aclk), // input wire aclk
.aresetn(reset), // 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 [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
.m_axis_data_tuser(m_axis_data_tuser), // output wire [7 : 0] m_axis_data_tuser
.event_fft_overflow(event_fft_overflow), // output wire event_fft_overflow
.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
);
这样一般就ok了。
5.关于AXIS协议。FFT 这么多线是不是头疼,其实如果你细心的话你会发现上面那个代码块被我分成了5部分。第一部分是时钟和复位,不再赘述,接下来是配置数据,输入端和输出端,最后是提示的一些信息。其中配置数据输入端和输出端是一样的协议。除了data外还有三根线axis_data_tvalid,axis_data_tready,axis_data_tlast。axis_data_tvalid是说向对方表示我数据准备好了,你可以进行传送了,axis_data_tready是对方向你说他数据准备好了可以传送了。通常在这两种都完成的情况下,数据就可以进行传送了,最后一根线axis_data_tlast是在最后一个数据时这个数据线拉高i,提示对方说我的数据传输完了。是这个意思。恩对。
6.关于FFT和IFFT。不得不说FFT蛮准的,跟MATLAB基本差不多。但是IFFT就emmmmm…先看一组数据
这个是仿真数据
这个是MATLAB做出来的结果
是不是感觉差别好大。。。 我心态都快炸了,感觉两个数据一点都不一样啊。但是你细心看,仿真得到的数据都等于MATLAB做出的数据乘以128,128是我的FFT点数,这样的话基本就ok了。原来这样子,IFFT做出来的结果统一要进行除以FFT点数的运算,才能得到和MATLAB一样的结果。
7.关于缩放因子。是这样的,比如MATLAB求出来的这个数是56,如果你的缩放因子是6’b000011的话,那你仿真得到的结果就是56/(2^3)=7.
行,大概就是这样子,有什么问题我再补充吧。接下来上一下测试代码和matlab生成需要变换数据文件的代码。要的,拿去。
//测试代码
`timescale 1ns / 1ps
module tb();
reg[15:0] memory[0:127];//申请128个16位的存储单元
reg[11:0] n;
initial
begin
$readmemb("F:/mem.txt",memory); //读取file1.txt中的数字到memory
for(n=0;n<128;n=n+1) //把八个存储单元的数字都读取出来,若存的数不到八个单元输出x态,程序结果中会看到
$display("%b",memory[n]);
end
reg aclk;
reg reset;
reg s_axis_config_tvalid;
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
reg m_axis_data_tready;
reg [15:0] s_axis_config_tdata;
reg [63:0] s_axis_data_tdata;
// Outputs
wire s_axis_config_tready;
wire s_axis_data_tready;
wire m_axis_data_tvalid;
wire m_axis_data_tlast;
wire event_frame_started;
wire event_tlast_unexpected;
wire event_tlast_missing;
wire event_status_channel_halt;
wire event_fft_overflow;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;
wire [63: 0] m_axis_data_tdata;
wire [7:0] m_axis_data_tuser;
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
fft fft_module (
.aclk(aclk), // input wire aclk
.aresetn(reset), // 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 [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
.m_axis_data_tuser(m_axis_data_tuser), // output wire [7 : 0] m_axis_data_tuser
.event_fft_overflow(event_fft_overflow), // output wire event_fft_overflow
.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
);
// generate clk
always #5 aclk =! aclk;
initial
begin
// Initialize Inputs
aclk = 0;
reset = 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;
#200;
reset = 1;
// Wait 100 ns for global reset to finish
#100;
m_axis_data_tready = 1;
s_axis_config_tvalid = 1;
s_axis_config_tdata = 15'b0000000000000000; // FFT
s_axis_data_tdata = 64'b0;
s_axis_data_tvalid = 0;
#1000;
for(n=0;n<128;n=n+1)
begin
#10
s_axis_data_tvalid <= 1;
s_axis_data_tdata <= {{48'b0},memory[n]};
$display("mem_a[%d] = %h", n, memory[n]);
if(n== 127)
s_axis_data_tlast <= 1;
else
s_axis_data_tlast <= 0;
end
#10;
s_axis_data_tlast <= 0;
s_axis_data_tdata = 64'h0000;
s_axis_data_tvalid = 0;
end
wire [31:0] m_data_im;
wire [31:0] m_data_re;
assign m_data_im = m_axis_data_tdata[63:32];
assign m_data_re = m_axis_data_tdata[31:0];
endmodule
%MATLAB生成数据
table = 0:127;
trans_table = str2num(dec2bin(table));
add = fopen('F:\mem.txt','w+');
fprintf(add,'%016d \n',trans_table);
fclose(add);
接着,是在FPGA上实现的代码,我前边有一个FIR,从RAM里读数据给FFT然后再做运算,可以参考。
`timescale 1ns / 1ps
module FFT(
//-------------------------输入-------------------------------------------------------------
input CLK_100M,
input reset,
input [31:0] FFT_Data,
input FFT_im_re, //前两个数是虚实还是实数虚数
input [11:0] FIR_add,
output FFT_input_start,
output reg [11:0] FFT_Data_address, //需要第几个地址
output [15:0] FFT_ans_add, //输出地址
output [31:0] FFT_ans_Data_re, //输出实部
output [31:0] FFT_ans_Data_im, //输出虚部
output FFT_ans_valid //FFT输出有效
);
//----------------------------------------------------------------------------------------------------
// IFFT例化
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 [63:0] m_axis_data_tdata;
wire [15: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;
IFFT IFFT_Module (
.aclk(CLK_100M), // input wire aclk
.aresetn(reset), // input wire aresetn
.s_axis_config_tdata(16'd0), // input wire [15 : 0] s_axis_config_tdata
.s_axis_config_tvalid(1'b1), // 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 [63 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output wire [15 : 0] m_axis_data_tuser
.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready(1'b1), // 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
);
//---------------------------------------------------------------------------------------------------------------
// 开始进行IFFT
reg one_end_flag;
always @ (posedge CLK_100M)
begin
if(FFT_Data_address == 12'd4095)
s_axis_data_tvalid <= 1'b0;
else if((FIR_add==12'd4095)&one_end_flag)
s_axis_data_tvalid <= 1'b1;
end
//---------------------------------------------------------------------------------------------------------------
// 只进行一帧
always @ (*)
begin
if(FFT_Data_address == 12'd4095)
one_end_flag = 1'b0;
else if(FIR_add==12'd4094)
one_end_flag = 1'b1;
end
//---------------------------------------------------------------------------------------------------------------
// 生成取数地址
reg [11:0] FFT_Data_address_n;
always @ (*)
begin
if(FFT_Data_address == 12'd4095)
FFT_Data_address_n = 12'd0;
else if(s_axis_data_tvalid&one_end_flag)
FFT_Data_address_n = FFT_Data_address +1'b1;
else
FFT_Data_address_n = 12'd0;
end
always @ (posedge CLK_100M or negedge reset)
begin
if(!reset)
FFT_Data_address = 12'd0;
else
FFT_Data_address <= FFT_Data_address_n ;
end
//---------------------------------------------------------------------------------------------------------------
// 虚实选择
always @ (posedge CLK_100M)
begin
if(FFT_im_re)
begin
if(FFT_Data_address[0])
s_axis_data_tdata <= {FFT_Data,32'b0};
else
s_axis_data_tdata <= {32'b0,FFT_Data};
end
else
begin
if(FFT_Data_address[0])
s_axis_data_tdata <= {32'b0,FFT_Data};
else
s_axis_data_tdata <= {FFT_Data,32'b0};
end
end
//---------------------------------------------------------------------------------------------------------------
// 最后一帧拉高
always @ (posedge CLK_100M or negedge reset)
begin
if(!reset)
s_axis_data_tlast <= 1'b0;
else
begin
if(FFT_Data_address==12'd4094)
s_axis_data_tlast <= 1'b1;
else
s_axis_data_tlast <= 1'b0;
end
end
//---------------------------------------------------------------------------------------------------------------
// 输出端口赋值
assign FFT_ans_add = m_axis_data_tuser;
assign FFT_ans_Data_re = m_axis_data_tdata[31:0];
assign FFT_ans_Data_im = m_axis_data_tdata[31:0];
assign FFT_ans_valid = m_axis_data_tvalid;
assign FFT_input_start = s_axis_data_tvalid;
initial
begin
s_axis_data_tlast = 1'b0;
s_axis_data_tdata = 64'd0;
s_axis_data_tvalid = 1'b0;
m_axis_data_tready = 1'b0;
FFT_Data_address_n = 12'd0;
one_end_flag = 1'b0;
end
endmodule
最后,吐槽下CSDN难用的编辑器,让我编辑这篇文章编辑了两遍,谢谢你。