参考博客: https://blog.csdn.net/shichaog/article/details/51189711
https://blog.csdn.net/qq_36375505/article/details/81742680
https://blog.csdn.net/yanshanyan/article/details/82386575
1、IP基础知识:
该ip用于实现N=2**m(m=3~16)点FFT的变换,
实现的数学类型包括:
A) 定点全精度
B) 定点缩减位宽
C) 块浮点
每一级蝶型运算后舍入或者取整。对于N点运算,FFT还是逆FFT,scaling策略以及循环前缀的长度是运行时可配置的,可随帧改变,改变变换点数会复位FFT ip核。
有四种可选择的FFT的实现架构:
1) PipelinedStreaming I/O
2) Radix-4Burst I/O
3) Radix-2Burst I/O
4) Radix-2 Lite Burst I/O
FFTip核使用基二和基四分解法计算离散傅里叶变换,对于Burst I/O architectures采用时域抽取法实现,对于Pipelined Streaming I/Oarchitecture.使用频域抽取法。当使用基四计算时,其蝶型算法的级数是log 4 (N),每一级包括N/4的基四蝶型运算。对于点数不是4的指数情况,则需要一个额外的基二来组合数据。类似的基二实现法需要log 2 (N)级蝶型运算。对于scaling方法,其每一级的scaling因子由s_axis_config_tdata来配置。Ip核的端口如下:
2、各端口介绍
整个IP的信号线可以分为三个部分:
- 三个AXI4-Stream的总线分别完成数据的输入输出和命令的输入。
- 时钟线和复位线是IP核的基本信号。
- 之后是一大堆的状态线,以event开头,标志了IP核的不同状态和遇到的各种问题。
下面简单说明一下AXI4-Stream:
-
总的来说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个时钟周期以上,之后送入配置命令即可。
其他信号
- Aclk输入时钟,上升沿有效
- Aclken :使用有效信号,高使能
- Aresetn:同步复位信号,低电平有效(至少保持aclk两个时钟周期)
- s_axis_config_tdata:包括配置信息,CP_LEN, FWD/INV, NFFT,SCALE_SCH.
3、IP 的datasheet
4、配置IP
1)
2)
3)
5、程序:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2018/12/10 17:16:18
// Design Name:
// Module Name: xfft_64text
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//module xfft_64text(aclk,aresetn,s_axis_config_tdata,s_axis_data_tlast,s_axis_data_tready,s_axis_config_tvalid,s_axis_config_tready,s_axis_data_tvalid,s_axis_data_tdata,m_axis_status_tready,m_axis_data_tdata,
//m_axis_data_tuser,m_axis_data_tvalid,m_axis_data_tready,m_axis_data_tlast,m_axis_status_tdata,m_axis_status_tvalid,event_frame_started,event_tlast_unexpected,event_tlast_missing,event_fft_overflow,
//event_status_channel_halt,event_data_in_channel_halt,event_data_out_channel_halt);
// input aclk;
// input aresetn;
// input [7:0] s_axis_config_tdata;
// input s_axis_data_tlast;
// output s_axis_data_tready;
// output s_axis_config_tready;
// input s_axis_config_tvalid;
// input s_axis_data_tvalid;
// input [31:0] s_axis_data_tdata;
// input m_axis_status_tready;
// output [31:0] m_axis_data_tdata;
// output [15:0] m_axis_data_tuser;
// output m_axis_data_tvalid;
// input m_axis_data_tready;
// output m_axis_data_tlast;
// output [7:0] m_axis_status_tdata;
// output m_axis_status_tvalid;
// 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;
// xfft_64 xfft_64(
// .aclk(aclk),
// .aresetn(aresetn),
// .s_axis_config_tdata(s_axis_config_tdata),
// .s_axis_data_tlast(s_axis_data_tlast),
// .s_axis_data_tready(s_axis_data_tready),
// .s_axis_config_tready(s_axis_config_tready),
// .s_axis_config_tvalid(s_axis_config_tvalid),
// .s_axis_data_tvalid(s_axis_data_tvalid),
// .s_axis_data_tdata(s_axis_data_tdata),
// .m_axis_status_tready(m_axis_status_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_tready(m_axis_data_tready),
// .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)
// );
//endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2018/12/10 17:07:53
// Design Name:
// Module Name: xfft_64_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module xfft_64text(
input aclk,
input aresetn,
input [15:0] xn_im,
input [15:0] xn_re,
input s_axis_data_tvalid,
input s_axis_data_tlast,
input s_axis_config_tvalid,
output s_axis_data_tready,
output [15:0] xk_im,
output [15:0] xk_re,
output m_axis_data_tvalid
);
wire [7 : 0] s_axis_config_tdata = 8'b0000001;
wire [31:0] m_axis_data_tdata;
wire [15:0] m_axis_data_tuser;
wire m_axis_data_tlast;
wire s_axis_config_tready;
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;
wire [31:0] s_axis_data_tdata = {xn_im,xn_re};
assign {xk_im,xk_re} = m_axis_data_tdata;
xfft_64 usr_FFT(
.aclk(aclk),
.aresetn(aresetn),
.s_axis_config_tdata(s_axis_config_tdata),
.s_axis_config_tvalid(s_axis_config_tvalid),
.s_axis_config_tready(s_axis_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_tready),
.s_axis_data_tlast(s_axis_data_tlast),
.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_tready(1'b1),
.m_axis_data_tlast(m_axis_data_tlast),
.event_frame_started(event_frame_started),
.event_tlast_unexpected(event_tlast_unexpected),
.event_tlast_missing(event_tlast_missing),
.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
测试程序:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2018/12/10 17:07:53
// Design Name:
// Module Name: xfft_64_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module xfft_64_tb();
reg aclk;
reg aresetn;
wire [15:0] xn_im;
wire [15:0] xn_re;
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
reg s_axis_config_tvalid;
reg [7:0] dat_c;
wire s_axis_data_tready;
wire [15:0] xk_im;
wire [15:0] xk_re;
wire m_axis_data_tvalid;
integer handle1;
initial
begin//sequence block
handle1 =$fopen("C:/Users/lyw/Desktop/fsave.txt");
#200000 $fclose(handle1);
$stop;
end
initial begin
aclk = 0;
s_axis_data_tvalid = 0;
s_axis_data_tlast = 0;
s_axis_config_tvalid = 0;
dat_c = 8'b0;
aresetn=0;
#200 aresetn = 1;
forever #10 aclk = ~aclk;
end
reg [15:0] cnt=0;
reg [15:0] index = 0;
always @(posedge aclk)
begin
if(aresetn)
begin
cnt <= cnt + 1'b1;
if(cnt == 0)
begin
s_axis_config_tvalid <=1;
end
else if(cnt == 3)
s_axis_config_tvalid <= 0;
else if(cnt == 6)
begin
s_axis_data_tvalid <= 1;
dat_c <= 0;
index = 0;
end
else if(cnt == 16'd69)
begin
s_axis_data_tlast <= 1'b1;
dat_c <= (dat_c + 4'b1000);
end
else if(cnt == 16'd70)
begin
s_axis_data_tvalid <= 1'b0;
s_axis_data_tlast <= 1'b0;
end
else
begin
dat_c <=(dat_c + 4'b1000);
end
if(s_axis_data_tvalid)
index <= index +1;
end
end
always @(posedge aclk)
begin
if(s_axis_data_tvalid)
$fwrite(handle1,"%d %d \n",xn_re,xn_im);
else if(m_axis_data_tvalid)
$fwrite(handle1,"%d %d \n",xk_re,xk_im);
end
assign xn_re ={13'b0,{dat_c[7]? ~dat_c[7:4] : dat_c[7:4]}};
assign xn_im =0;
xfft_64text xfft_64_inst(
.aclk(aclk),
.aresetn(aresetn),
.xn_im(xn_im),
.xn_re(xn_re),
.s_axis_data_tvalid(s_axis_data_tvalid),
.s_axis_data_tlast(s_axis_data_tlast),
.s_axis_config_tvalid(s_axis_config_tvalid),
.s_axis_data_tready(s_axis_data_tready),
.xk_im(xk_im),
.xk_re(xk_re),
.m_axis_data_tvalid(m_axis_data_tvalid)
);
endmodule
matlab:验证程序
clear;
file_name='C:/Users/lyw/Desktop/fsave.txt';
fid = fopen(file_name,'r');
c = fscanf(fid,'%d');
fclose(fid);
%有符号数
for i=1: length(c)
if(c(i)>32767)
b(i) = c(i)-65536;
else b(i) = c(i);
end
end
d1=b(1:2:end);
d2=b(2:2:end);
comp1=d1(1:64) + j*d2(1:64);
comp2=d1(65:128) + j*d2(65:128);
c1avr=sum(comp1)/length(comp1);
c1=comp1-c1avr;
% c1=comp1;
c1fft=abs(fft(c1,64));
c2fft=abs(comp2);
plot(c1);
figure
subplot(2,1,1);
plot(c1fft);
subplot(2,1,2);
plot(c2fft);
figure
subplot(2,1,1);
plot(c1fft(1:20));
subplot(2,1,2);
plot(c2fft(1:20));
结果:
数据表现了良好的一致性;
注:其实数据不是很完美,
输出的第一个数据是224,要是0则数据很一致,原因正在寻找中。。。。。。