目录
1、FFT IP核简介
Vivado FFT IP核是Xilinx公司推出的针对FPGA设备的快速傅里叶变换专用IP核。它提供了一个高效的硬件解决方案来执行频域分析,广泛应用于数字信号处理领域,如无线通信、雷达系统和音频处理等。通过利用FPGA的并行处理能力,FFT IP核能够处理高速数据流,实现低延迟和高吞吐量的信号变换。它不仅可以用于正向FFT转换,还可以通过逆FFT支持频域信号的重构,本文对FFT和IFFT进行配置仿真验证。
2、数据流程
ADC 采样数据首先通过一个异步跨时钟域 FIFO 进行缓冲。该 FIFO 的写时钟(100 MHz)与 ADC 采样率匹配,读时钟(300 MHz)或者工作在更高频率以确保数据的高速稳定输出。我们通过控制读、写使能信号,维持 FIFO 在一个动态平衡中,合理深度(即不能写满和读空)的前提下精确管理数据的读、写速率。
从 FIFO 高速读出的数据流被依次送入 FFT IP 核进行处理。鉴于 FFT IP 核本身存在固有的处理延迟,为了确保经过整个处理流程(包括 FFT 和后续的 IFFT)后的数据连续性,选定的 FFT 变换长度(512点)需要小于 IFFT 变换的长度(1024点),最后通过同步FIFO将数据输出。整体流程如下图所示。
3、顶层模块代码
顶层模块主要实现数据的跨时钟的处理,实现fifo的动态平衡。
`timescale 1 ns / 10ps
//
module adc_iq_cail
#( BIT_NUM = 24
)(
input SYS_CLK , // (input )
input SYS_RSTN , // (input )
input [BIT_NUM-1'b1:0] I_DATA_IN , // (input )
input [BIT_NUM-1'b1:0] Q_DATA_IN , // (input )
input DATA_IN_VALID , // (input )
output [BIT_NUM-1'b1:0] I_DATA_OUT , // (output)
output [BIT_NUM-1'b1:0] Q_DATA_OUT , // (output)
output DATA_OUT_VALID // (output)
);
localparam FFT_LEN = 512 ;
reg locrstn,locrstn_buf ;
//=================================================================================/
// fifo
//=================================================================================/
wire fifo_rd_en ;
wire [47 : 0] fifo_dout ;
wire fifo_full ;
wire fifo_empty ;
wire fifo_valid ;
wire fifo_wr_rst_busy ;
wire fifo_rd_rst_busy ;
reg [15:0] fifo_read_cunt ;
reg [15:0] data_cunt ;
wire [12:0] wr_data_count ;
//=================================================================================/
// FFT
//=================================================================================/
reg [15:0] tlast_cnt ;
wire fft_tlast_path ;
wire [47:0] fft_data_tdata ;
wire fft_tvalid_path ;
wire fft_tready_path ;
wire m_axis_data_tvalid ;
wire [47:0] m_dds_tdata ;
//=================================================================================/
// 状态机
//=================================================================================/
reg [2:0] fifo_read_state ;
reg [2:0] fifo_next__state ;
parameter FIFO_READ_IDLE = 'd0 ;
parameter FIFO_READ_WAIT = 'd1 ;
parameter FIFO_READ = 'd2 ;
parameter FIFO_READ_DONE = 'd3 ;
always@(posedge clk_300m or negedge locked)begin
if(locked == 1'b0)begin
locrstn_buf <= 1'b0;
locrstn <= 1'b0;
end else begin
locrstn_buf <= 1'b1;
locrstn <= locrstn_buf;
end
end
//=================================================================================/
// 生成仿真数据
//=================================================================================/
dds_compiler_0 dds_compiler_1m (
.aclk (clk_100m ), // input wire aclk
.s_axis_phase_tvalid (1'b1 ), // input wire s_axis_phase_tvalid
.s_axis_phase_tdata (16'd655 ), // input wire [15 : 0] s_axis_phase_tdata
.m_axis_data_tvalid (m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (m_dds_tdata ) // output wire [47 : 0] m_axis_data_tdata
);
//=================================================================================/
// 状态机 控制FIFO数据流
//=================================================================================/
always @(posedge clk_300m or posedge locrstn) begin
if( locrstn ==1'b0)
fifo_read_state <= FIFO_READ_IDLE;
else
fifo_read_state <= fifo_next__state;
end
// always @(*) begin
always @(posedge clk_300m or posedge locrstn) begin
case (fifo_read_state)
FIFO_READ_IDLE : fifo_next__state = FIFO_READ_WAIT;
// FIFO_READ_WAIT : fifo_next__state = (wr_data_count>=1100)&&(data_cunt<=5) ? FIFO_READ : FIFO_READ_WAIT;
FIFO_READ_WAIT : fifo_next__state = ((fft_tready_path==1'b1)&&(wr_data_count>1100)) ? FIFO_READ : FIFO_READ_WAIT;
FIFO_READ : fifo_next__state = fft_tlast_path ? FIFO_READ_DONE : FIFO_READ;
FIFO_READ_DONE : fifo_next__state = FIFO_READ_IDLE;
default : fifo_next__state = FIFO_READ_IDLE;
endcase
end
always@(posedge clk_300m or negedge locrstn)begin
if(locrstn==1'b0)
data_cunt<='d0;
else if(data_cunt==30)
data_cunt<=data_cunt;
else if(fft_tlast_path)begin
data_cunt<=data_cunt+1'b1;
end
else
data_cunt<=data_cunt;
end
//=================================================================================/
//----------------------------------------FIFO模块---------------------------------
//=================================================================================/
fifo_ddc2fft_48bit u_fifo_ddc2fft_48bit (
.wr_clk (clk_100m ), // input wire wr_clk
.rd_clk (clk_300m ), // input wire rd_clk
.din (m_dds_tdata ), // input wire [47 : 0] din
.wr_en (m_axis_data_tvalid ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (fifo_dout ), // output wire [47 : 0] dout
.full (fifo_full ), // output wire full
.empty (fifo_empty ), // output wire empty
.valid (fifo_valid ), // output wire valid
.wr_data_count (wr_data_count ) // output wire [12 : 0] wr_data_count
);
//=================================================================================/
// 产生FIFO读使能信号fifo_rd_en,在FFT核准备好且FIFO非空时
//=================================================================================/
always@(posedge clk_300m or negedge locrstn) begin
if(locrstn==1'b0)
fifo_read_cunt<='d0;
else if(fifo_read_state == FIFO_READ)begin
fifo_read_cunt<=fifo_read_cunt+1'b1;
end
else
fifo_read_cunt<='d0;
end
//=================================================================================/
//用于产生FFT模块每帧输入最后(第1024个数据)一个数据的控制信息s_axis_data_tlast
//=================================================================================/
always@(posedge clk_300m or negedge locrstn) begin
if(locrstn==1'b0)
tlast_cnt<='d0;
else if((tlast_cnt==FFT_LEN-1)&&(fifo_valid==1'b1)||(fifo_read_state != FIFO_READ))
tlast_cnt<='d0;
else if(fifo_valid==1'b1)
tlast_cnt<=tlast_cnt+1'b1;
end
assign fifo_rd_en = (fft_tready_path==1'b1) && (1<=fifo_read_cunt)&& (fifo_read_cunt<=FFT_LEN)&& (fifo_empty==1'b0)? 1'b1 : 1'b0;
// assign fifo_rd_en = (1<=fifo_read_cunt)&& (fifo_read_cunt<FFT_LEN+1)&& (fifo_empty==1'b0)? 1'b1 : 1'b0;
//-----------------------------------------FFT模块----------------------------------------------
//=================================================================================/
//输入的正弦信号为实信号放在实部
//=================================================================================/
assign fft_data_tdata = fifo_dout;
assign fft_tvalid_path = fifo_valid;
assign fft_tlast_path = ((tlast_cnt==FFT_LEN-1)&&(fifo_valid)) ? 1'b1 : 1'b0;
cail_fft_ifft #(
.BIT_NUM ( 24 ) //BIT_NUM
)u_cail_fft_ifft
(
.SYS_CLK (clk_300m ), // (input ) (input )
.SYS_RSTN (locrstn ), // (input ) (input )
.fft_data_tdata (fft_data_tdata ), // (input ) (input )
.fft_tvalid_path (fft_tvalid_path ), // (input ) (input )
.fft_tlast_path (fft_tlast_path ), // (input ) (input )
.fft_tready_path (fft_tready_path ), // (output ) (output )
.I_DATA_OUT ( ), // (output) (output)
.Q_DATA_OUT ( ), // (output) (output)
.DATA_OUT_VALID ( ) // (output) (output)
);
endmodule
3.2 异步FIFO配置
4、FFT和IFF处理模块
// +FHDR============================================================================/
// Author :
// Creat Time : 2024/09/23 14:07:27
// File Name : cail_fft_ifft.v
// Module Ver : V1.0
//
// CopyRight(c) 2024, UNI_T
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
// ------------------------------
// | |
// | -^- -^- |
// | |
// | -<>- |
// | |
// ------------------------------
//
//
//
//
//
//
//
//
//
//
//
// Modification History:
// V1.0 initial
//
// -FHDR============================================================================/
//
//
//
//
`timescale 1 ns / 10ps
//
module cail_fft_ifft
#( parameter BIT_NUM = 32
)(
input pcie_user_clk , // (input )
input pcie_user_rst_n , // (input )
input SYS_CLK , // (input )
input SYS_RSTN , // (input )
input caild_en , // (input )
input fft_cail_init_flag , // (input )
input [31:0] fft_cail_init_data , // (input )
input fft_cail_init_en , // (input )
(*mark_debug = "true"*)input [BIT_NUM*2-1'b1 : 0] fft_data_tdata , // (input )
(*mark_debug = "true"*)input fft_tvalid_path , // (input )
(*mark_debug = "true"*)input fft_tlast_path , // (input )
(*mark_debug = "true"*)output fft_tready_path , // (output)
(*mark_debug = "true"*)output [31:0] I_DATA_OUT , // (output)
(*mark_debug = "true"*)output [31:0] Q_DATA_OUT , // (output)
(*mark_debug = "true"*)output DATA_OUT_VALID // (output)
);
//=================================================================================/
// REST
//=================================================================================/
reg rstn_buf,rstn ;
reg fft_rst ;
//=================================================================================/
// FFT CONFIG
//=================================================================================/
reg [1:0] fft_ip_state ;
reg [15:0] fft_config_dat ;
reg [15:0] ifft_config_dat ;
reg fft_config_tvalid ;
wire fft_config_tdy_path ;
wire ifft_config_tdy_path ;
//=================================================================================/
// FFT DATA
//=================================================================================/
wire [BIT_NUM*2-1'b1 : 0] fft_m_axis_data_tdata ;
// wire [79 : 0] fft_m_axis_data_tdata ;
wire [15 : 0] fft_m_axis_data_tuser ;
wire fft_m_axis_data_tvalid ;
wire fft_m_axis_data_tlast ;
//=================================================================================/
// IFFT DATA
//=================================================================================/
wire [BIT_NUM*2-1'b1 : 0] ifft_m_axis_data_tdata ;
// wire [95 : 0] ifft_m_axis_data_tdata ;
wire [15 : 0] ifft_m_axis_data_tuser ;
wire ifft_m_axis_data_tvalid ;
wire ifft_m_axis_data_tlast ;
wire ifft_tready_path ;
reg [BIT_NUM*2-1'b1 : 0] m_axis_data ;
// reg [79 : 0] m_axis_data ;
reg m_axis_tlast ;
reg m_axis_tvalid ;
//=================================================================================/
// CAIL DATA
//=================================================================================/
wire [31 : 0] fft_cail_dout ;
reg [BIT_NUM + 'd15 : 0] FFT_DATA_I ;
reg [BIT_NUM + 'd15 : 0] FFT_DATA_Q ;
reg FFT_DATA_VLD ;
reg FFT_DATA_LAST ;
//=================================================================================/
//DATA 截位
//=================================================================================/
wire fft_data_cbit_i ;
wire fft_data_cbit_q ;
wire [31 : 0] fft_data_round_i ;
wire [31 : 0] fft_data_round_q ;
wire ifft_data_cbit_i ;
wire ifft_data_cbit_q ;
wire [23 : 0] ifft_data_round_i ;
wire [23 : 0] ifft_data_round_q ;
wire [7 : 0] ifft_m_axis_status_tdata ;
wire ifft_m_axis_status_tvalid ;
wire ifft_m_axis_status_tready ;
reg [7 : 0] ifftdat_delay ;
reg ifftdat_vlid ;
always@(posedge SYS_CLK or negedge SYS_RSTN)
begin
if(SYS_RSTN == 1'b0)begin
rstn_buf <= 1'b0;
rstn <= 1'b0;
end else begin
rstn_buf <= 1'b1;
rstn <= rstn_buf;
end
end
always@(posedge SYS_CLK or negedge rstn)
begin
if(rstn == 1'b0)begin
fft_rst <= 1'b0;
fft_ip_state <= 2'd0;
fft_config_tvalid <= 1'b0;
fft_config_dat <= {7'd0,1'b1,3'b000,5'b01001};
ifft_config_dat <= {7'd0,1'b0,3'b000,5'b01001};
end
else begin
case(fft_ip_state)
2'd0:begin
fft_rst <= 1'b1;
fft_ip_state <= 2'd1;
end
2'd1:begin
fft_ip_state <= 2'd2;
fft_config_dat <= {7'd0,1'b1,3'b000,5'b01001};
ifft_config_dat <= {7'd0,1'b0,3'b000,5'b01001};
fft_config_tvalid <= 1'b1;
end
2'd2:begin
if(fft_config_tdy_path==1'b1)
begin
fft_config_tvalid <= 1'b0;
fft_ip_state <= 2'd3;
end
else;
end
2'd3:begin
fft_ip_state <= 2'd3;
end
default:fft_ip_state <= 2'd0;
endcase
end
end
//生成FFT的IP模块
fft_cail u_fft_cail (
.aclk ( SYS_CLK ), // input wire aclk
.aresetn ( fft_rst ), // input wire aresetn
// .s_axis_config_tdata ( fft_config_dat ), // input wire [15 : 0] s_axis_config_tdata
.s_axis_config_tdata ( 8'd1 ), // input wire [15 : 0] s_axis_config_tdata
.s_axis_config_tvalid ( fft_config_tvalid ), // input wire s_axis_config_tvalid
.s_axis_config_tready ( fft_config_tdy_path ), // output wire s_axis_config_tready
.s_axis_data_tdata ( fft_data_tdata ), // input wire [47 : 0] s_axis_data_tdata
.s_axis_data_tvalid ( fft_tvalid_path ), // input wire s_axis_data_tvalid
.s_axis_data_tready ( fft_tready_path ), // output wire s_axis_data_tready
.s_axis_data_tlast ( fft_tlast_path ), // input wire s_axis_data_tlast
.m_axis_data_tdata ( fft_m_axis_data_tdata ), // output wire [47 : 0] m_axis_data_tdata
.m_axis_data_tuser ( ), // output wire [7 : 0] m_axis_data_tuser
// .m_axis_data_tready ( 1'b1 ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready
.m_axis_data_tready ( ifftdat_vlid ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready
.m_axis_data_tvalid ( fft_m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tlast ( fft_m_axis_data_tlast ), // output wire m_axis_data_tlast
.m_axis_status_tdata ( ), // output wire [7 : 0] m_axis_status_tdata
.m_axis_status_tvalid ( ), // output wire m_axis_status_tvalid
.m_axis_status_tready ( 1'b1 ), // input wire m_axis_status_tready
.event_frame_started ( ), // output wire event_frame_started
.event_tlast_unexpected ( ), // output wire event_tlast_unexpected
.event_tlast_missing ( ), // output wire event_tlast_missing
.event_data_in_channel_halt ( ), // output wire event_data_in_channel_halt
.event_status_channel_halt ( ), // output wire event_status_channel_halt
.event_data_out_channel_halt ( ) // output wire event_data_out_channel_halt
);
always@(posedge SYS_CLK or negedge rstn)
begin
if(rstn == 1'b0)begin
m_axis_data <= 'd0;
m_axis_tlast <= 1'b0;
m_axis_tvalid <= 1'b0;
end else begin
m_axis_data <= fft_m_axis_data_tdata;
m_axis_tlast <= fft_m_axis_data_tlast;
m_axis_tvalid <= fft_m_axis_data_tvalid;
end
end
always@(posedge SYS_CLK or negedge rstn)
begin
if(rstn == 1'b0)begin
FFT_DATA_I <= 'd0;
FFT_DATA_Q <= 'd0;
FFT_DATA_VLD <= 1'b0;
FFT_DATA_LAST <= 1'b0;
end
else begin
if(m_axis_tvalid == 1'b1)begin
FFT_DATA_I <= m_axis_data[32+:32]*fft_cail_dout[15: 0] - m_axis_data[0 +:32]*fft_cail_dout[31:16] ;
FFT_DATA_Q <= m_axis_data[32+:32]*fft_cail_dout[31:16] + m_axis_data[0 +:32]*fft_cail_dout[15: 0] ;
FFT_DATA_VLD <= 1'b1;
end
else begin
FFT_DATA_VLD <= 1'b0;
FFT_DATA_I <= 'd0;
FFT_DATA_Q <= 'd0;
end
FFT_DATA_LAST <= m_axis_tlast;
end
end
assign fft_data_cbit_i = FFT_DATA_I[47]?(FFT_DATA_I[14]&(|FFT_DATA_I[13:0])):FFT_DATA_I[14];
assign fft_data_round_i = FFT_DATA_I[46-:32]+fft_data_cbit_i;
assign fft_data_cbit_q = FFT_DATA_Q[47]?(FFT_DATA_Q[14]&(|FFT_DATA_Q[13:0])):FFT_DATA_Q[14];
assign fft_data_round_q = FFT_DATA_Q[46-:32]+fft_data_cbit_q;
reg [63:0] IFFT_DATA_IN ;
reg IFFT_DATA_VALID_IN ;
wire cail_data_chose ;
always@(posedge SYS_CLK or negedge rstn)
begin
if(rstn == 1'b0)begin
IFFT_DATA_IN <= 'd0;
IFFT_DATA_VALID_IN <= 1'b0;
end
else begin
if(caild_en == 1'b1)begin
IFFT_DATA_IN <= {fft_data_round_i,fft_data_round_q};
IFFT_DATA_VALID_IN <= FFT_DATA_VLD;
end
else begin
IFFT_DATA_IN <= m_axis_data;
IFFT_DATA_VALID_IN <= m_axis_tvalid;
end
end
end
//生成IFFT的IP模块
ifft_cail u_ifft_cail (
.aclk ( SYS_CLK ), // input wire aclk
.aresetn ( fft_rst ), // input wire aresetn
.s_axis_config_tdata ( ifft_config_dat ), // input wire [15 : 0] s_axis_config_tdata
// .s_axis_config_tdata ( 8'b0 ), // input wire [15 : 0] s_axis_config_tdata
.s_axis_config_tvalid ( fft_config_tvalid ), // input wire s_axis_config_tvalid
.s_axis_config_tready ( ifft_config_tdy_path ), // output wire s_axis_config_tready
.s_axis_data_tdata ( IFFT_DATA_IN ), // input wire [47 : 0] s_axis_data_tdata
.s_axis_data_tvalid ( IFFT_DATA_VALID_IN ), // input wire s_axis_data_tvalid
.s_axis_data_tready ( ifft_tready_path ), // output wire s_axis_data_tready
.s_axis_data_tlast ( ), // input wire s_axis_data_tlast
.m_axis_data_tdata ( ifft_m_axis_data_tdata ), // output wire [47 : 0] m_axis_data_tdata
// .m_axis_data_tready ( 1'b1 ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready
.m_axis_data_tready ( ifftdat_vlid ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready
.m_axis_data_tvalid ( ifft_m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tlast ( ifft_m_axis_data_tlast ), // output wire m_axis_data_tlast
.m_axis_status_tdata (ifft_m_axis_status_tdata ), // output wire [7 : 0] m_axis_status_tdata
.m_axis_status_tvalid (ifft_m_axis_status_tvalid ), // output wire m_axis_status_tvalid
.m_axis_status_tready ( 1'b1 ), // input wire m_axis_status_tready
.event_frame_started ( ), // output wire event_frame_started
.event_tlast_unexpected ( ), // output wire event_tlast_unexpected
.event_tlast_missing ( ), // output wire event_tlast_missing
.event_data_in_channel_halt ( ), // output wire event_data_in_channel_halt
.event_status_channel_halt ( ), // output wire event_status_channel_halt
.event_data_out_channel_halt ( ) // output wire event_data_out_channel_halt
);
always@(posedge SYS_CLK or negedge rstn)
begin
if(rstn == 1'b0)begin
ifftdat_delay <= 6'd6;
ifftdat_vlid <= 1'b0;
end else begin
if(ifftdat_delay >= 6'd31)begin//fft 取数延时,使得最后一级fifo 能够无损传输数据给ps
ifftdat_delay <= 6'd0;
ifftdat_vlid <= 1'b1;
end else begin
ifftdat_delay <= ifftdat_delay + 1'b1;
ifftdat_vlid <= 1'b0;
end
end
end
reg fifo_rd_en ;
reg [5 : 0] fifo_rd_cunt ;
wire [63 : 0] dout ;
wire [9 : 0] data_count ;
wire full ;
wire empty ;
wire valid ;
ifft_fifo_data_300m u_ifft_fifo_data_300m(
.clk (SYS_CLK ), // input wire rd_clk
.din (ifft_m_axis_data_tdata ), // input wire [75 : 0] din
.wr_en (ifft_m_axis_data_tvalid ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (dout ), // output wire [63 : 0] dout
.data_count (data_count ), // output wire [12 : 0] wr_data_count
.full (full ), // output wire full
.empty (empty ), // output wire empty
.valid (valid ) // output wire valid
);
always@(posedge SYS_CLK or negedge rstn)
begin
if(rstn == 1'b0)begin
fifo_rd_en <= 1'b0;
end else begin
if(empty==1'b0)
fifo_rd_en <= 1'b1;
else
fifo_rd_en <= 1'b0;
end
end
assign I_DATA_OUT = dout[63-:32] ;
assign Q_DATA_OUT = dout[31-:32] ;
assign DATA_OUT_VALID = valid ;
endmodule
4.1 FFT配置界面
4.2 IFFT配置界面
4.3 SYNC_FIFO配置界面
5、仿真
5.1、testbench代码
仿真时用dds模拟adc产生数据,并且控制输入6次数据,做FFT、IFFT后连续输出
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/08/12 14:14:51
// Design Name:
// Module Name: cail_testbench
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module cail_testbench;
reg clk = 0 ;
reg rst_n = 0 ;
wire clk_300m ;
wire clk_100m ;
wire locked ;
initial
begin
rst_n =0;
#100;
rst_n =1;
end
always #5 clk = ~clk;
// clk_wiz_1 instance_name
// (
// // Clock out ports
// .clk_out1 (clk_100m ), // output clk_out1
// .clk_out2 (clk_300m ), // output clk_out2
// // Status and control signals
// .reset (!rst_n ), // input reset
// .locked ( ), // output locked
// // Clock in ports
// .clk_in1 (clk ) // input clk_in1
// );
globaclk_clk300m u_globaclk_clk300m
(
// Clock out ports
.clk_300m_g (clk_300m ), // output clk_300_g
.clk_100m_g (clk_100m ), // output clk_100_g
// Status and control signals
.reset (1'b0 ), // input reset
.locked (locked ), // output locked
// Clock in ports
.global_clk (clk ) // input global_clk
);
reg [47 : 0] m_dds_tdata_r;
reg [31 : 0] m_dds_tdata_cunt;
reg m_dds_tdata_valid;
always@(posedge clk_300m or negedge locrstn)begin
if(locrstn==1'b0)begin
m_dds_tdata_cunt<='d0;
m_dds_tdata_r<='d0;
m_dds_tdata_valid<='d0;
end
else if(m_dds_tdata_cunt == 'd2) begin
m_dds_tdata_cunt<='d0;
m_dds_tdata_r<=m_dds_tdata;
m_dds_tdata_valid<='d1;
end
else begin
m_dds_tdata_cunt<=m_dds_tdata_cunt + 'd1;
m_dds_tdata_r <= m_dds_tdata_r;
m_dds_tdata_valid<='d0;
end
end
localparam FFT_LEN = 512 ;
reg locrstn,locrstn_buf ;
//=================================================================================/
// fifo
//=================================================================================/
wire fifo_rd_en ;
wire [47 : 0] fifo_dout ;
wire fifo_full ;
wire fifo_empty ;
wire fifo_valid ;
wire fifo_wr_rst_busy ;
wire fifo_rd_rst_busy ;
(*mark_debug = "true"*)reg [15:0] fifo_read_cunt ;
reg [15:0] data_cunt ;
wire [10:0] wr_data_count ;
//=================================================================================/
// FFT
//=================================================================================/
reg [15:0] tlast_cnt ;
wire fft_tlast_path ;
wire [47:0] fft_data_tdata ;
wire fft_tvalid_path ;
wire fft_tready_path ;
wire m_axis_data_tvalid ;
wire [47:0] m_dds_tdata ;
//=================================================================================/
// 状态机
//=================================================================================/
reg [2:0] fifo_read_state ;
reg [2:0] fifo_next__state ;
parameter FIFO_READ_IDLE = 'd0 ;
parameter FIFO_READ_WAIT = 'd1 ;
parameter FIFO_READ = 'd2 ;
parameter FIFO_READ_DONE = 'd3 ;
always@(posedge clk_300m or negedge locked)begin
if(locked == 1'b0)begin
locrstn_buf <= 1'b0;
locrstn <= 1'b0;
end else begin
locrstn_buf <= 1'b1;
locrstn <= locrstn_buf;
end
end
//=================================================================================/
// 状态机 控制FIFO数据流
//=================================================================================/
always @(posedge clk_300m or posedge locrstn) begin
if( locrstn ==1'b0)
fifo_read_state <= FIFO_READ_IDLE;
else
fifo_read_state <= fifo_next__state;
end
always @(*) begin
// always @(posedge clk_300m or posedge locrstn) begin
case (fifo_read_state)
FIFO_READ_IDLE : fifo_next__state = FIFO_READ_WAIT;
FIFO_READ_WAIT : fifo_next__state = (wr_data_count>=1500)&&(data_cunt<=5) ? FIFO_READ : FIFO_READ_WAIT;//仿真时连续6次输入数据
// FIFO_READ_WAIT : fifo_next__state = ((fft_tready_path==1'b1)&&(wr_data_count>1100)) ? FIFO_READ : FIFO_READ_WAIT;
FIFO_READ : fifo_next__state = fft_tlast_path ? FIFO_READ_DONE : FIFO_READ;
// FIFO_READ : fifo_next__state = (fifo_read_cunt==FFT_LEN) ? FIFO_READ_DONE : FIFO_READ;
FIFO_READ_DONE : fifo_next__state = FIFO_READ_IDLE;
default : fifo_next__state = FIFO_READ_IDLE;
endcase
end
always@(posedge clk_300m or negedge locrstn)begin
if(locrstn==1'b0)
data_cunt<='d0;
else if(data_cunt==30)
data_cunt<=data_cunt;
else if(fft_tlast_path)begin
data_cunt<=data_cunt+1'b1;
end
else
data_cunt<=data_cunt;
end
//=================================================================================/
//----------------------------------------FIFO模块---------------------------------
//=================================================================================/
fifo_ddc2fft_48bit u_fifo_ddc2fft_48bit (
.wr_clk (clk_300m ), // input wire wr_clk
.rd_clk (clk_300m ), // input wire rd_clk
.din (m_dds_tdata_r ), // input wire [47 : 0] din
.wr_en (m_dds_tdata_valid ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (fifo_dout ), // output wire [47 : 0] dout
.full (fifo_full ), // output wire full
.empty (fifo_empty ), // output wire empty
.valid (fifo_valid ), // output wire valid
.wr_data_count ( wr_data_count ) // output wire [12 : 0] wr_data_count
);
//=================================================================================/
// 产生FIFO读使能信号fifo_rd_en,在FFT核准备好且FIFO非空时
// 在使能信号连续拉高1024个周期以后等待3个周期再拉高,用于分割一次1024长度的FFT
//=================================================================================/
always@(posedge clk_300m or negedge locrstn) begin
if(locrstn==1'b0)
fifo_read_cunt<='d0;
else if(fifo_read_state == FIFO_READ)begin
fifo_read_cunt<=fifo_read_cunt+1'b1;
end
else
fifo_read_cunt<='d0;
end
//=================================================================================/
//用于产生FFT模块每帧输入最后(第1024个数据)一个数据的控制信息s_axis_data_tlast
//=================================================================================/
always@(posedge clk_300m or negedge locrstn) begin
if(locrstn==1'b0)
tlast_cnt<='d0;
else if((tlast_cnt==FFT_LEN-1)&&(fifo_valid==1'b1)||(fifo_read_state != FIFO_READ))
tlast_cnt<='d0;
else if(fifo_valid==1'b1)
tlast_cnt<=tlast_cnt+1'b1;
end
assign fifo_rd_en = (fft_tready_path==1'b1) && (1<=fifo_read_cunt)&& (fifo_read_cunt<=FFT_LEN)&& (fifo_empty==1'b0)? 1'b1 : 1'b0;
// assign fifo_rd_en = (1<=fifo_read_cunt)&& (fifo_read_cunt<FFT_LEN+1)&& (fifo_empty==1'b0)? 1'b1 : 1'b0;
//-----------------------------------------FFT模块----------------------------------------------
//=================================================================================/
//输入的正弦信号为实信号放在实部
//=================================================================================/
assign fft_data_tdata = fifo_dout;
assign fft_tvalid_path = fifo_valid;
assign fft_tlast_path = ((tlast_cnt==FFT_LEN-1)&&(fifo_valid)) ? 1'b1 : 1'b0;
dds_compiler_0 dds_compiler_1m (
.aclk (clk_100m ), // input wire aclk
.s_axis_phase_tvalid (1'b1 ), // input wire s_axis_phase_tvalid
.s_axis_phase_tdata (16'd655 ), // input wire [15 : 0] s_axis_phase_tdata
.m_axis_data_tvalid (m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (m_dds_tdata ) // output wire [47 : 0] m_axis_data_tdata
);
cail_fft_ifft #(
.BIT_NUM ( 24 ) //BIT_NUM
)u_cail_fft_ifft
(
.SYS_CLK (clk_300m ), // (input ) (input )
.SYS_RSTN (locrstn ), // (input ) (input )
.fft_data_tdata (fft_data_tdata ), // (input ) (input )
.fft_tvalid_path (fft_tvalid_path ), // (input ) (input )
.fft_tlast_path (fft_tlast_path ), // (input ) (input )
.fft_tready_path (fft_tready_path ), // (output ) (output )
.I_DATA_OUT ( ), // (output) (output)
.Q_DATA_OUT ( ), // (output) (output)
.DATA_OUT_VALID ( ) // (output) (output)
);
////////仿真数据保存为TXT文件
////integer dout_file_imag;
////
////initial
////begin
//// dout_file_imag =$fopen("F:/shx/Matalb/test/f_imag.txt");
//// if(dout_file_imag == 0)begin
//// $display("can not open file!");
//// $stop;
//// end
////end
////always @(posedge clk_300m)
////begin
//// if(m_axis_data_tvalid) begin
//// $fdisplay(dout_file_imag,"%d",$signed(f_imag));
//// end
////end
endmodule