Quartus做FFT(详细看这篇就够了)

废话:暑假在家没事,就用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

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值