废话:暑假在家没事,就用FPGA做了FFT,一开始用的Quartus13.0做FFT,试了好长时间生成不了FFTip和,后面更新了quartus18.0就可以了,但用Modesim仿真还是不成功(后面了解到了自己下载的Modesim确实alter库),过了一段时间想到了不用Modesim,用在线逻辑分析仪,就成功解决了。
1:准备工作
1:Quartus的FFT IP核属于收费IP,如果是个人学习使用要对IP核单独破解。(参考https://blog.csdn.net/fpgadesigner/article/details/80605869 中的破解步骤)。
2:下载modelsim,这个modelsim不能用自己下载的modelsim,去官网下载,对应版本的modelsim-altera版本,已经将altera上的器件的lib编译好,如果自己下载modelsim使用,则还要自己编译相应的altera库,
3:不用Modesim用在线逻辑分析仪,具体可参考正点原子或者野火FPGA教程
2:正式工作
生成FFTip核
里面参数意义这里不做讲解参考在quartus中使用FFT IP核最全教程(从入门到放弃)_quartus fft ip核-CSDN博客
module FFT_top
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [7:0] data_in ,
output wire sink_valid ,
output wire [7:0] data_modulus ,
output wire data_sop ,
output wire data_eop ,
output wire data_valid ,
output wire [9:0] index
);
wire sink_ready ;
wire sink_sop ;
wire sink_eop ;
wire source_valid ;
wire source_ready ;
wire source_sop ;
wire source_eop ;
wire [1:0] sink_error ;
wire [1:0] source_error;
wire [5:0] source_exp ;
wire [8:0] source_real ;
wire [8:0] source_imag ;
FFT_ctrl FFT_ctrl_U1
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.source_eop(source_eop ),
.sink_valid(sink_valid ),
.sink_ready(sink_ready ),
.sink_error(sink_error ),
.sink_sop (sink_sop ),
.source_ready(source_ready),
.sink_eop (sink_eop )
);
FFT FFT_U2
(
.clk (sys_clk ), // 输入 clk.clk
.reset_n (sys_rst_n ), // 输入 rst.reset_n
.sink_valid (sink_valid), // 输入sink.sink_valid
.sink_ready (sink_ready), // 输入 .sink_ready
.sink_error (sink_error), // 输入 .sink_error
.sink_sop (sink_sop ), // 输入 .sink_sop
.sink_eop (sink_eop ), // 输入 .sink_eop
.sink_real ({1'b0,data_in}), // 输入 .sink_real
.sink_imag (9'd0 ), // 输入 .sink_imag
.inverse (1'b0 ), // 输入 .inverse
.source_valid (source_valid), // 输出 source.source_valid
.source_ready (source_ready), // 输入 .source_ready
.source_error (source_error), // 输出 .source_error
.source_sop (source_sop ), // 输出 .source_sop
.source_eop (source_eop ), // 输出 .source_eop
.source_real (source_real ), // 输出 .source_real
.source_imag (source_imag ), // 输出 .source_imag
.source_exp (source_exp ) // 输出 .source_exp
);
data_modulus data_modulus_U3
(
.clk_50m (sys_clk ) ,
.rst_n (sys_rst_n ) ,
.source_real (source_real ) ,
.source_imag (source_imag ) ,
.source_sop (source_sop ) ,
.source_eop (source_eop ) ,
.source_valid(source_valid ) ,
.data_modulus(data_modulus ) ,
.data_sop (data_sop ) ,
.data_eop (data_eop ) ,
.data_valid (data_valid ) ,
.index (index)
);
endmodule
module FFT_ctrl
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire source_eop ,
output reg sink_valid ,
output wire sink_ready ,
output wire sink_error ,
output reg sink_sop ,
output wire source_ready,
output reg sink_eop
);
reg [9:0] fft_cnt ;
assign sink_ready = 1'b1;
assign sink_error = 2'b00;
assign source_ready = 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
fft_cnt <= 10'd0;
else if(source_eop == 1'b1)
fft_cnt <= 10'd0;
else if(fft_cnt == 10'd300)
fft_cnt = 10'd300;
else
fft_cnt <= fft_cnt+10'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
sink_sop <= 1'b0;
else if(fft_cnt == 10'd1)
sink_sop <= 1'b1;
else
sink_sop <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
sink_eop <= 1'b0;
else if(fft_cnt == 10'd256)
sink_eop <= 1'b1;
else
sink_eop <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
sink_valid <= 1'b0;
else if((fft_cnt >= 10'd1)&&(fft_cnt <= 10'd256))
sink_valid <= 1'b1;
else
sink_valid <= 1'b0;
endmodule
module data_modulus(
input clk_50m,
input rst_n,
input [8:0] source_real,
input [8:0] source_imag,
input source_sop,
input source_eop,
input source_valid,
output [7:0] data_modulus,
output reg data_sop,
output reg data_eop,
output reg [9:0] index ,
output reg data_valid
);
//reg define
reg [15:0] source_data;
reg [7:0] data_real;
reg [7:0] data_imag;
reg data_sop1;
reg data_sop2;
reg data_eop1;
reg data_eop2;
reg data_valid1;
reg data_valid2;
//*****************************************************
//** main code
//*****************************************************
//取实部和虚部的平方和
always @ (posedge clk_50m or negedge rst_n) begin
if(!rst_n) begin
source_data <= 16'd0;
data_real <= 8'd0;
data_imag <= 8'd0;
end
else begin
if(source_real[8]==1'b0) //由补码计算原码
data_real <= source_real;
else
data_real <= ~source_real + 1'b1;
if(source_imag[8]==1'b0) //由补码计算原码
data_imag <= source_imag;
else
data_imag <= ~source_imag + 1'b1;
//计算原码平方和
if(data_valid1==1'b1)
source_data <= (data_real*data_real) + (data_imag*data_imag);
else
source_data <=16'd0;
end
end
//例化sqrt模块,开根号运算
sqrt sqrt_inst
(
.clk (clk_50m ),
.radical (source_data ),
.q (data_modulus),
.remainder ( )
);
//数据取模运算共花费了三个时钟周期,此处延时三个时钟周期
always @ (posedge clk_50m or negedge rst_n) begin
if(!rst_n) begin
data_sop <= 1'b0;
data_sop1 <= 1'b0;
data_sop2 <= 1'b0;
data_eop <= 1'b0;
data_eop1 <= 1'b0;
data_eop2 <= 1'b0;
data_valid <= 1'b0;
data_valid1 <= 1'b0;
data_valid2 <= 1'b0;
end
else begin
data_valid1 <= source_valid;
data_valid2 <= data_valid1;
data_valid <= data_valid2;
data_sop1 <= source_sop;
data_sop2 <= data_sop1;
data_sop <= data_sop2;
data_eop1 <= source_eop;
data_eop2 <= data_eop1;
data_eop <= data_eop2;
end
end
always @ (posedge clk_50m or negedge rst_n)
if(~rst_n)
index <= 10'd0;
else if(data_valid==1'b0)
index <= 10'd0;
else if(data_valid==1'b1)
index <= index + 1'b1;
endmodule
运行结果这里输入的是195KH的信号,代码运行结果也是195KH,
计算方法参考正点原子的音频FFT,
最最最重要的是
FFTip核输出的source实部和虚部是带有符号位的,因此输入要大于实际值一位,输出的最高位表示符号位,别的正常写
原文链接:https://blog.csdn.net/youzjuer/article/details/121320018
原文链接:https://blog.csdn.net/FPGADesigner/article/details/80690345