ISE
FFT_ip your_instance_name (
.aclk(aclk), // input aclk
.s_axis_config_tdata(s_axis_config_tdata), // input [7 : 0] s_axis_config_tdata
.s_axis_config_tvalid(s_axis_config_tvalid), // input s_axis_config_tvalid
.s_axis_config_tready(s_axis_config_tready), // output s_axis_config_tready
.s_axis_data_tdata(s_axis_data_tdata), // input [31 : 0] s_axis_data_tdata
.s_axis_data_tvalid(s_axis_data_tvalid), // input s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready), // output s_axis_data_tready
.s_axis_data_tlast(s_axis_data_tlast), // input s_axis_data_tlast
.m_axis_data_tdata(m_axis_data_tdata), // output [31 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output [7 : 0] m_axis_data_tuser
.m_axis_data_tvalid(m_axis_data_tvalid), // output m_axis_data_tvalid
.m_axis_data_tready(m_axis_data_tready), // input m_axis_data_tready
.m_axis_data_tlast(m_axis_data_tlast), // output m_axis_data_tlast
.m_axis_status_tdata(m_axis_status_tdata), // output [7 : 0] m_axis_status_tdata
.m_axis_status_tvalid(m_axis_status_tvalid), // output m_axis_status_tvalid
.m_axis_status_tready(m_axis_status_tready), // input m_axis_status_tready
.event_frame_started(event_frame_started), // output event_frame_started
.event_tlast_unexpected(event_tlast_unexpected), // output event_tlast_unexpected
.event_tlast_missing(event_tlast_missing), // output event_tlast_missing
.event_status_channel_halt(event_status_channel_halt), // output event_status_channel_halt
.event_data_in_channel_halt(event_data_in_channel_halt), // output event_data_in_channel_halt
.event_data_out_channel_halt(event_data_out_channel_halt) // output event_data_out_channel_halt
);
端口说明:
input aclk,输入数据的采样频率;
input [7 : 0] s_axis_config_tdata ,一般写8'd1,最低位1表示fft,0表示ifft;如果scaling设置自动,该端口8位宽,若scaling设置不是自动,会是16位宽;
input s_axis_config_tvalid,当configure数据有效时,置1后模块会采集configure数据;如果在采样时刻该位为0,那么模块会跳过该次采样,只有当采样时刻该位为1是,模块才会采数;
output s_axis_config_tready,模块准备好接受configure数据的标志;
input [31 : 0] s_axis_data_tdata,输入数据,高16位位虚部,低16位为实部;
input s_axis_data_tvalid,当输入数据有效时,置1后模块会采集数据;
output s_axis_data_tready,模块准备好接受数据的标志;
input s_axis_data_tlast,输入数据流是该次转换的最后一个数据时,置1,告诉模块一帧数据结束;
output [31 : 0] m_axis_data_tdata,输出数据,高16位位虚部,低16位为实部;
output [7 : 0] m_axis_data_tuser,设置为自动scaling时,该端口表示该次转换的截位(压缩倍数);如果scaling不是自动,那么不会有该信号;该信号在一帧数据的整个时间段内都有效;
output m_axis_data_tvalid,输出数据有效标志(指示);
input m_axis_data_tready,告诉模块准备好接受数据了,模块可以输出转换结果了,该信号由从机(下一个模块)产生,一般应该一直保持高电平,即从机不应该影响主机的性能,如果该信号为0了,可能会导致模块吐不出数,最终导致模块不吃数(只是一种可能,没试过,突然产生的想法)
output m_axis_data_tlast,输出一帧数据的最后一位指示;
output [7 : 0] m_axis_status_tdata,和m_axis_data_tuser内容一样,只不过只在一帧数据的开始位置保持一个时钟;
output m_axis_status_tvalid,status数据有效标志;
input m_axis_status_tready,类似于m_axis_data_tready的作用;
output event_frame_started,输入数据的一帧数据的开始标志,模块告诉数据输入端一帧数据开始采集;
output event_tlast_unexpected,
output event_tlast_missing,若果输入数据流的last信号不对(最常见的就是错位),这两个信号会给出警告指示;
output event_status_channel_halt
output event_data_in_channel_halt
output event_data_out_channel_halt,这三个信号都为0,说明一般不会出错
代码:
(1)TOP 模块
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 10:30:06 08/07/2018
// Design Name:
// Module Name: FFT_top
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module FFT_top #(
parameter integer width_data_y_in = 16,
parameter integer width_addr_y_in = 9
)(
clk,
rst_n,
en_bram_y_in,
wea_bram_y_in,
data_y_in,
data_imag,
data_real
);
input clk;
input rst_n;
input en_bram_y_in;
input [width_data_y_in/8:1]wea_bram_y_in;
output [width_data_y_in:1]data_y_in;
output [width_data_y_in:1]data_imag,data_real;
//FFT端口:
wire s_axis_config_tready;
wire [8:1]s_axis_config_tdata;
wire s_axis_data_tvalid,s_axis_data_tready,s_axis_data_tlast;
wire [width_data_y_in*2:1] s_axis_data_tdata;
wire [width_data_y_in*2:1] m_axis_data_tdata;
wire [7 : 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_status_channel_halt;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;
//PLL端口:
wire CLK_OUT_250M,LOCKED;
//所有的模块都准备好了
wire ready_top;
assign ready_top = (rst_n) & (LOCKED) ;
//原始数据:
wire [width_addr_y_in:1] addr_bram_y_in;
Bram_ctrl #(
.width_addr(width_addr_y_in)
)U_Bram_ctrl_bram1(
.clk (CLK_OUT_250M),
.rst_n (ready_top),
.ena (en_bram_y_in & s_axis_data_tready),
.addr (addr_bram_y_in)
);
Bram_y_in U_Bram_y_in (
.clka(CLK_OUT_250M), // input clka
.ena(en_bram_y_in), // input ena
.wea(wea_bram_y_in), // input [1 : 0] wea
.addra(addr_bram_y_in), // input [6 : 0] addra
.dina(16'd0), // input [15 : 0] dina
.douta(data_y_in) // output [15 : 0] douta
);
//FFT:
reg [7:0] reg_s_axis_config_tdata;
reg reg_s_axis_config_tvalid;
always@(posedge CLK_OUT_250M or negedge rst_n)
begin
if(~rst_n)
begin
reg_s_axis_config_tdata <= 0;
reg_s_axis_config_tvalid <= 0;
end
else
begin
reg_s_axis_config_tdata <= 8'd1;
reg_s_axis_config_tvalid <= 1;
end
end
assign s_axis_config_tdata = reg_s_axis_config_tdata;
assign s_axis_config_tvalid = reg_s_axis_config_tvalid;
assign s_axis_data_tvalid = ready_top & en_bram_y_in;
assign s_axis_data_tdata[width_data_y_in*2:width_data_y_in+1] = 16'd0;
assign s_axis_data_tdata[width_data_y_in:1] = data_y_in;
assign s_axis_data_tlast = (addr_bram_y_in == 8'd255) ? 1'b1:1'b0;//255是单次FFT的点数;
assign data_imag = m_axis_data_tdata[32:17];
assign data_real = m_axis_data_tdata[16:1];
FFT_ip U_FFT_ip (
.aclk(CLK_OUT_250M), // input aclk
.s_axis_config_tdata(s_axis_config_tdata), // input [7 : 0] s_axis_config_tdata
.s_axis_config_tvalid(s_axis_config_tvalid), // input s_axis_config_tvalid
.s_axis_config_tready(s_axis_config_tready), // output s_axis_config_tready
.s_axis_data_tdata(s_axis_data_tdata), // input [31 : 0] s_axis_data_tdata
.s_axis_data_tvalid(s_axis_data_tvalid), // input s_axis_data_tvalid
.s_axis_data_tready(s_axis_data_tready), // output s_axis_data_tready
.s_axis_data_tlast(s_axis_data_tlast), // input s_axis_data_tlast
.m_axis_data_tdata(m_axis_data_tdata), // output [31 : 0] m_axis_data_tdata
.m_axis_data_tuser(m_axis_data_tuser), // output [7 : 0] m_axis_data_tuser
.m_axis_data_tvalid(m_axis_data_tvalid), // output m_axis_data_tvalid
.m_axis_data_tready(1'b1), // input m_axis_data_tready
.m_axis_data_tlast(m_axis_data_tlast), // output m_axis_data_tlast
.m_axis_status_tdata(m_axis_status_tdata), // output [7 : 0] m_axis_status_tdata
.m_axis_status_tvalid(m_axis_status_tvalid), // output m_axis_status_tvalid
.m_axis_status_tready(1'b1), // input m_axis_status_tready
.event_frame_started(event_frame_started), // output event_frame_started
.event_tlast_unexpected(event_tlast_unexpected), // output event_tlast_unexpected
.event_tlast_missing(event_tlast_missing), // output event_tlast_missing
.event_status_channel_halt(event_status_channel_halt), // output event_status_channel_halt
.event_data_in_channel_halt(event_data_in_channel_halt), // output event_data_in_channel_halt
.event_data_out_channel_halt(event_data_out_channel_halt) // output event_data_out_channel_halt
);
PLL U_PLL
(// Clock in ports
.CLK_IN_100M(clk), // IN
// Clock out ports
.CLK_OUT_250M(CLK_OUT_250M), // OUT
// Status and control signals
.RESET(~rst_n),// IN
.LOCKED(LOCKED)); // OUT
endmodule
(2)Bram_Ctrl模块
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 07:36:19 08/01/2018
// Design Name:
// Module Name: bram_ctrl
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//一个clk吐一个数;ena为使能信号;所有的数吐完为止;
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module Bram_ctrl #(
parameter integer width_addr = 1
)(
clk,
rst_n,
ena,
addr
);
// pwm_cs <= {{(CHANNEL-1){1'b0}},1'b1};
input clk;
input rst_n;
input ena;
output [width_addr:1]addr;
wire [width_addr:1]addr_max;
assign addr_max = {(width_addr){32'hffff}};
//ena延迟一个时钟,(时序要求)
reg reg_ena;
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
reg_ena <= 0;
end
else
begin
reg_ena <= ena;
end
end
//地址信号:
reg [width_addr:1]reg_addr;
always@(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
reg_addr <= 0;
end
else
begin
if(reg_ena)
begin
if(reg_addr==addr_max)//
begin
// reg_addr <= reg_addr ;//只输出一遍
reg_addr <= reg_addr + 1;//循环输出
end
else
begin
reg_addr <= reg_addr + 1;
end
end
else
begin
reg_addr <= reg_addr;
end
end
end
assign addr = reg_addr;
endmodule
(3)Bram模块
16*512;单口ram;有ena信号;read first;有wea信号(bytesize=8);
(4)PLL模块
产生250M的时钟,其实输入时钟50M直接驱动也是可以的;
说点题外话:
另外当一个模块内有比较复杂的时钟系统(多个PLL)时,一定要注意BUFG等的使用(PLL的输出端口可以选择BUFG)