前面我们已经讲解过Xilinx中FFT IP的使用,但是使用的时候IP的配置接口我们没有进行相应的讲解,直接使用GUI配置好的接口,这在现实应用中很不方方便,会让人感觉到还不如自己手写一个FFT算法,当然博主也可完全手撕FFT、CORDIC代码,但是把IP用好了绝对比我们手写的代码要好用的多。这篇博客主要讲解FFT IP的重配置及其参数的意义,最后将给出Modelsim与MATLAB的两盒验证。 本次实验所使用的软硬件环境如下: 这里再多说一句,从博主之前的文章中可以发现MATLAB在信号处理中的正确性,所以绝对不要说MATLAB不重要。而且一般Xilinx的IP核都可以生成相应的m文件,也就是说我们可以实现MATLAB与Modelsim完全一致的验证。 所以要想做信号处理或算法得FPGA实现一定要掌握MATLAB。 我们在定制FFT IP核得时候就已经对FFT进行了配置,但是我们实际使用IP得时候经常可以碰见IP得重配置,这一块内容直至一年前我进行PLL得重配置得时候还是无从下手,但是这篇文章我们主要讲解FFT IP得重配置,可以让大家学习到Xilinx IP重配置得设计技巧。这里我们首先强调技术手册得重要性,因为市面上没有这方面得资料,所以我们要学习相应IP得重配置必须学习技术手册。我们首先看FFT IP得技术手册如下: 首先我们来看FFT IP核的接口引脚: 从FFT IP技术手册的首页我们可以发现,FFT可以完成的功能: 要想配置上面的这些信息,我们就一定要进行配置数据的输入,配置数据的不同位数代表不同的功能,如下: tx_ifft_op模块: ifft_op_map模块: fft_sig_comp模块: 上面的代码联系之前的理论部分,便可以学会FFT的重配置,包括经过这篇博客的学习要学会其他Xilinx常用IP的重配置,比如:DDS、FIR等等。 tb_tx_ifft_op模块: 有关MATLAB对FFT IP核调用的部分,我们上篇博客已经进行了详细的讲解,在这里我们将给出MATLAB与Modelsim生成的数据相对比的代码: 运行结果如下: [1]、电子发烧友学院 创作不易,认为文章有帮助的同学们可以关注、、转发支持。为行业贡献及其微小的一部分。或者对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:项目简述
1、VIVADO 2019.1
2、Modelsim 10.7
3、MATLAB 2015bFFT进行重配置
总共不到100页,是值得浏览一遍的,因为其他得IP基本上也是这几部分。C Model我们上篇博客已经进行了介绍,主要是为了我们在MATLAB中验证该模块得正确性来使用的。
其中FFT的接口主要可以分为6组如上图:
1、FFT的重配置接口
2、FFT的数据输入接口,遵循AXI-Stream协议
3、FFT的时钟、时钟使能、复位信号(注意复位信号要多给几个时钟)
4、FFT的数据输出接口,遵循AXI-Stream协议
5、可以输出FFT IP的当前的状态(一般不常使用)
6、可以输出一些FFT的错误信息,比如输入的last未知不正确或没有,数据溢出等等
上面是简要介绍了FFT IP的接口描述。具体的功能引脚的定义还是需要我们查找技术手册,我们这篇博客主要讲解IP的重配置,不会对AXI-Stream进行过多的介绍。
上面也是我们进行重配置的主要内容:
1、FFT最大变换的点数
2、FFT正变换还是逆变换
3、每级蝶形运算缩放因子的输入
4、CP_LEN的长度(这个具体的所用,我也不知道,知道的同学可以在评论里讨论一下)
上面为什么会有PAD,主要是因为字节对齐,每个配置功能占整数个字节。其中除了SCALE_SCH上面的位宽都是确定的,如下:
上面每位的取值情况如下:
上面的功能需要大家仔细读,尤其是SCALE_SCH,这里我给大家稍微解读一下。
1、每两个比特位构成的数字作为一级蝶形运算的缩放比例。2位比特位构成了0,1,2,3,这三个数代表分别代表蝶形运算之后的结果移位的个数。
2、SCALE_SCH的位数对于基-4 FFT算法是
2∗ceil(2NFFT),其中ceil是指向上取整;对于基-2 FFT算法是
2∗NFFT,相信熟悉FFT蝶形运算的同学很容易明白,其实这就是蝶形运算的个数然后乘以2。
关于FFT重配置的理论我们就讲到这里,下面我们给出相应的代码供大家学习,并且将代码与上篇博客中的MATLAB生成的结果相互验证,从而使得MATLAB与VIVADO实现双重验证。FPGA代码
FPGA逻辑代码
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : tx_ifft_op.v // Create Time : 2020-06-04 16:33:48 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module tx_ifft_op( input sclk , input rst_n , input cfg_vld , output reg p1_start , input s_config_tvalid , input [29:0] s_config_tdata , input s_data_tvalid , input [23:0] s_data_tdata , input s_data_tlast , output reg s_axis_config_tready , output reg s_axis_data_tready , output reg [31:0] m_axis_data_tdata , output [23:0] m_axis_data_tuser , output reg m_axis_data_tvalid , input m_axis_data_tready , output reg m_axis_data_tlast , output [ 7:0] m_axis_status_tdata , output m_axis_status_tvalid , input m_axis_status_tready , 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 , output [ 9:0] NOFDM ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ reg [ 9:0] NOFDM_CNT ; wire [39:0] s_axis_config_tdata ; wire s_axis_config_tvalid ; wire [31:0] s_axis_data_tdata ; wire s_axis_data_tvalid ; wire s_axis_data_tlast ; wire [ 4:0] NFFT ; wire [13:0] SCALE_SCH ; wire [11:0] RE_DATA ; wire [11:0] IM_DATA ; wire DATA_LAST ; wire DATA_EN ; wire FWD_INV ; wire fft_config_en ; wire [31:0] m_axis_data_tdata_store ; wire m_axis_data_tvalid_store; wire m_axis_data_tlast_store ; reg p1_start_D ; wire [12:0] CP_LEN ; reg last_delay ; wire Neg_ifft_tlast ; reg [ 4:0] rstn_cnt ; wire s_axis_data_tready1 ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign Neg_ifft_tlast = last_delay&&(~m_axis_data_tlast_store); always@(posedge sclk) last_delay <= m_axis_data_tlast_store; always @(posedge sclk) if(rst_n == 1'b0) NOFDM_CNT <= 10'd0; else if(NOFDM_CNT == NOFDM+1'b1 && NOFDM != 10'd0) NOFDM_CNT <= 10'd0; else if(Neg_ifft_tlast == 1'b1) NOFDM_CNT <= NOFDM_CNT + 1'b1; always @(posedge sclk) if(rst_n == 1'b0) rstn_cnt <= 5'h1f; else if(cfg_vld == 1'b1) rstn_cnt <= 5'd0; else if(rstn_cnt == 5'h1f) rstn_cnt <= rstn_cnt; else rstn_cnt <= rstn_cnt + 1'b1; always @(posedge sclk) if(rst_n == 1'b0) p1_start <= 1'b0; else if(rstn_cnt == 5'h1e) p1_start <= 1'b1; else if(NOFDM_CNT == NOFDM+1'b1 && NOFDM != 10'd0) p1_start <= 1'b1; else p1_start <= 1'b0; always @(posedge sclk) if(rst_n == 1'b0) s_axis_data_tready <= 1'b1; else if(Neg_ifft_tlast == 1'b1) s_axis_data_tready <= 1'b1; else if(s_data_tlast == 1'b1) s_axis_data_tready <= 1'b0; always @(posedge sclk) p1_start_D <= p1_start; always @(posedge sclk) if(rst_n == 1'b0) s_axis_config_tready <= 1'b0; else if(p1_start_D == 1'b1) s_axis_config_tready <= 1'b0; else if(Neg_ifft_tlast == 1'b1) s_axis_config_tready <= 1'b1; always @(posedge sclk) begin m_axis_data_tdata <= m_axis_data_tdata_store; m_axis_data_tvalid <= m_axis_data_tvalid_store && m_axis_data_tready; m_axis_data_tlast <= m_axis_data_tlast_store; end ifft_op_map ifft_op_map ( .sclk (sclk ), .rst_n (rst_n ), .s_config_tvalid (s_config_tvalid ), .s_config_tdata (s_config_tdata ), .s_data_tvalid (s_data_tvalid ), .s_data_tdata (s_data_tdata ), .s_data_tlast (s_data_tlast ), .RE_DATA (RE_DATA ), .IM_DATA (IM_DATA ), .DATA_EN (DATA_EN ), .DATA_LAST (DATA_LAST ), .fft_config_en (fft_config_en ), .NFFT (NFFT ), .CP_LEN (CP_LEN ), .SCALE_SCH (SCALE_SCH ), .FWD_INV (FWD_INV ), .NOFDM (NOFDM ) ); /*=================================================================== ====================================================================*/ fft_sig_comp fft_sig_comp ( .sclk (sclk ), .rst_n (rst_n ), .P1_EN (DATA_EN ), .RE_P1_DATA (RE_DATA ), .IM_P1_DATA (IM_DATA ), .data_LAST (DATA_LAST ), .fft_config_en (fft_config_en ), .NFFT (NFFT ), .CP_LEN (CP_LEN ), .SCALE_SCH (SCALE_SCH ), .FWD_INV (FWD_INV ), .s_axis_config_tdata (s_axis_config_tdata ), .s_axis_config_tvalid (s_axis_config_tvalid ), .s_axis_data_tdata (s_axis_data_tdata ), .s_axis_data_tvalid (s_axis_data_tvalid ), .s_axis_data_tlast (s_axis_data_tlast ) ); tx_xfft_0 tx_xfft_0 ( .aclk (sclk ), .aresetn (rst_n ), .s_axis_config_tdata (s_axis_config_tdata ), .s_axis_config_tvalid (s_axis_config_tvalid ), .s_axis_config_tready (sim_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_tready1 ), .s_axis_data_tlast (s_axis_data_tlast ), .m_axis_data_tdata (m_axis_data_tdata_store ), .m_axis_data_tuser (m_axis_data_tuser ), .m_axis_data_tvalid (m_axis_data_tvalid_store ), .m_axis_data_tready (m_axis_data_tready ), .m_axis_data_tlast (m_axis_data_tlast_store ), .m_axis_status_tdata (m_axis_status_tdata ), .m_axis_status_tvalid (m_axis_status_tvalid ), .m_axis_status_tready (m_axis_status_tready ), .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 // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : ifft_op_map.v // Create Time : 2020-06-04 16:49:13 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module ifft_op_map ( input sclk , input rst_n , input s_config_tvalid , input [29:0] s_config_tdata , input s_data_tvalid , input [23:0] s_data_tdata , input s_data_tlast , output reg [11:0] RE_DATA , output reg [11:0] IM_DATA , output reg DATA_EN , output reg DATA_LAST , output reg fft_config_en , output reg [ 4:0] NFFT , output reg [12:0] CP_LEN , output reg [13:0] SCALE_SCH , output reg FWD_INV , output reg [ 9:0] NOFDM ); /*=================================================================== ====================================================================*/ wire [ 1:0] fft_mode ; wire [ 9:0] nofdm ; wire [ 2:0] cp_pro ; wire [13:0] scale ; wire inv ; reg [ 2:0] PRO ; reg [ 1:0] MODE ; reg [ 1:0] MODE1 ; reg [ 9:0] NOFDM1 ; reg [ 2:0] PRO1 ; reg [13:0] SCALE_SCH1 ; reg FWD_INV1 ; reg fft_config_en1 ; assign fft_mode = s_config_tdata[1:0]; assign nofdm = s_config_tdata[11:2]; assign cp_pro = s_config_tdata[14:12]; assign scale = s_config_tdata[28:15]; assign inv = s_config_tdata[29]; always @(posedge sclk) begin if(rst_n == 1'b0)begin MODE1 <= 2'b00; NOFDM1 <= 10'd0; PRO1 <= 3'b000; SCALE_SCH1 <= 14'd0; FWD_INV1 <= 1'b0; end else if(s_config_tvalid)begin MODE1 <= fft_mode; NOFDM1 <= nofdm; PRO1 <= cp_pro; SCALE_SCH1 <= scale; FWD_INV1 <= inv; end end always@(posedge sclk)begin MODE <= MODE1; NOFDM <= NOFDM1; PRO <= PRO1; SCALE_SCH <= SCALE_SCH1; FWD_INV <= FWD_INV1; end always @(posedge sclk)begin RE_DATA <= s_data_tdata[23:12]; IM_DATA <= s_data_tdata[11:0]; DATA_EN <= s_data_tvalid; DATA_LAST <= s_data_tlast; end always@(posedge sclk) begin fft_config_en1 <= s_config_tvalid; fft_config_en <= fft_config_en1; end always @(posedge sclk) if(PRO1 == 3'd0) CP_LEN <= 13'd0; else if(PRO1 == 3'd1)//1/32 CP_LEN <= 13'd32; else if(PRO1 == 3'd2)//1/16 CP_LEN <= 13'd64; else if(PRO1 == 3'd3)//1/8; CP_LEN <= 13'd128; else if(PRO1 == 3'd4)//1/4; CP_LEN <= 13'd256; else CP_LEN <= 13'd0; always @(posedge sclk) case(MODE1) 2'b00: NFFT <= 5'b01010;//1k 2'b01: NFFT <= 5'b01011;//2k 2'b10: NFFT <= 5'b01100;//4k 2'b11: NFFT <= 5'b01101;//8k default:NFFT <= 5'b00000; endcase endmodule
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : fft_sig_comp.v // Create Time : 2020-06-04 16:55:01 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module fft_sig_comp( input sclk , input rst_n , input P1_EN , input [11:0] RE_P1_DATA , input [11:0] IM_P1_DATA , input data_LAST , input fft_config_en , input [ 4:0] NFFT , input [12:0] CP_LEN , input [13:0] SCALE_SCH , input FWD_INV , output [39:0] s_axis_config_tdata , output s_axis_config_tvalid, output [31:0] s_axis_data_tdata , output s_axis_data_tvalid , output s_axis_data_tlast ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ reg [39:0] s_axis_config_tdata_reg ; reg s_axis_config_tvalid_reg; reg [31:0] s_axis_data_tdata_reg ; reg s_axis_data_tvalid_reg ; reg s_axis_data_tlast_reg ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign s_axis_config_tdata = s_axis_config_tdata_reg; assign s_axis_config_tvalid = s_axis_config_tvalid_reg; assign s_axis_data_tdata = s_axis_data_tdata_reg; assign s_axis_data_tvalid = s_axis_data_tvalid_reg; assign s_axis_data_tlast = s_axis_data_tlast_reg; always @(posedge sclk) s_axis_config_tdata_reg <= {1'b0,SCALE_SCH,FWD_INV,3'b000,CP_LEN,3'b000,NFFT}; always @(posedge sclk) s_axis_config_tvalid_reg <= fft_config_en; always @(posedge sclk) s_axis_data_tdata_reg <= {4'b0000,IM_P1_DATA,4'b0000,RE_P1_DATA}; always @(posedge sclk) s_axis_data_tvalid_reg <= P1_EN; always @(posedge sclk) s_axis_data_tlast_reg <= data_LAST; endmodule
FPGA测试代码
`timescale 1ns / 1ps module tb_tx_ifft_op; reg sclk ; reg rst_n ; reg cfg_vld ; reg s_config_tvalid ; reg [29:0] s_config_tdata ; reg s_data_tvalid; reg s_data_tvalid_delay,s_data_tvalid_delay1; reg [23:0] s_data_tdata; reg s_data_tlast; reg m_axis_data_tready ; reg m_axis_status_tready ; wire s_axis_config_tready ; wire s_axis_data_tready ; wire [31:0]m_axis_data_tdata ; wire [23: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_fft_overflow ; wire event_status_channel_halt ; wire event_data_in_channel_halt ; wire event_data_out_channel_halt ; wire [9:0] NOFDM ; wire p1_start ; reg [1:0] fft_mode ; reg [9:0] nofdm ; reg [2:0] cp_pro ; reg [13:0]scale ; reg inv ; reg [11:0]re_data ; reg [11:0]im_data ; always @(posedge sclk) begin s_data_tvalid_delay <= s_data_tvalid; s_data_tvalid_delay1 <= s_data_tvalid_delay; end initial begin #0; sclk =1'b0; rst_n=1'b0; cfg_vld = 1'b0; m_axis_data_tready = 1'b1; m_axis_status_tready = 1'b1; s_config_tvalid = 1'b0; s_config_tdata = 30'd0; fft_mode=2'b01; nofdm = 10'd1; cp_pro = 3'b000; scale = 14'b01_0110_1010_1010; //scale = 14'd0; inv = 1'b0; s_data_tvalid = 1'b0; s_data_tlast = 1'b0; repeat(1) @(posedge sclk)#1; cfg_vld = 1'b1; repeat(1) @(posedge sclk)#1; cfg_vld = 1'b0; repeat(30) @(posedge sclk)#1; rst_n =1'b1; repeat(30) @(posedge sclk)#1; s_config_tvalid = 1'b1; s_config_tdata = {inv,scale,cp_pro,nofdm,fft_mode}; repeat(1) @(posedge sclk)#1; s_config_tvalid = 1'b0; repeat(300) @(posedge sclk)#1; s_data_tvalid = 1'b1; s_data_tlast = 1'b0; repeat(1) @(posedge sclk)#1; s_config_tvalid = 1'b0; repeat(2047) @(posedge sclk)#1; s_data_tlast = 1'b0; s_data_tvalid = 1'b0;//mark for test repeat(1) @(posedge sclk)#1; s_data_tlast = 1'b1; repeat(1) @(posedge sclk)#1; s_data_tlast = 1'b0; end always #10 sclk = ~sclk; //========================================================================= // input //========================================================================= integer fid1; integer fid2; initial begin fid2 = $fopen("IM_DATA.txt","r"); fid1 = $fopen("RE_DATA.txt","r"); end always@(posedge sclk) begin if(s_data_tvalid)begin $fscanf(fid1,"%d",re_data); $fscanf(fid2,"%d",im_data); end end always @(posedge sclk) begin s_data_tdata <= {re_data,im_data}; end //========================================================================= // output //========================================================================= wire signed [11:0] re_out; wire signed [11:0] im_out; assign re_out = {m_axis_data_tdata[15],m_axis_data_tdata[10:0]}; assign im_out = {m_axis_data_tdata[31],m_axis_data_tdata[26:16]}; integer fid3; initial begin fid3 = $fopen("re_fft_data.txt","w"); end always@(posedge sclk) begin if(m_axis_data_tvalid) $fwrite(fid3,"%dn",re_out); end integer fid4; initial begin fid4 = $fopen("im_fft_data.txt","w"); end always@(posedge sclk) begin if(m_axis_data_tvalid) $fwrite(fid4,"%dn",im_out); end tx_ifft_op uut ( .sclk (sclk ), .rst_n (rst_n ), .cfg_vld (cfg_vld ), .p1_start (p1_start ), .s_config_tvalid (s_config_tvalid ), .s_config_tdata (s_config_tdata ), .s_data_tvalid (s_data_tvalid_delay1 ), .s_data_tdata (s_data_tdata ), .s_data_tlast (s_data_tlast ), .m_axis_data_tready (m_axis_data_tready ), .m_axis_status_tready (m_axis_status_tready ), .s_axis_config_tready (s_axis_config_tready ), .s_axis_data_tready (s_axis_data_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_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), .NOFDM (NOFDM ) ); endmodule
MATLAB验证
clc; clear all; load fft_data_com.mat sim_options = struct(... 'MODE', '2k' ... %fft模式 1k 2k 4k 8k ); tx_nFrame=1; %------------------------------------------------------------------------------ % Parameters Definition %------------------------------------------------------------------------------ switch sim_options.MODE case '1k' NFFT = 1024; % FFT number of points case '2k' NFFT = 2048; % FFT number of points case '4k' NFFT = 4096; % FFT number of points case '8k' NFFT = 8192; % FFT number of points otherwise, error('sim_options UNKNOWN MODE'); end fid1 = fopen('re_fft_data.txt','r'); real_data_sim = fscanf(fid1,'%d'); fid1 = fopen('im_fft_data.txt','r'); imag_data_sim = fscanf(fid1,'%d'); start_Idx = NFFT*(tx_nFrame - 1); if(isempty(real_data_sim)) real_data_result = 0; imag_data_result = 0; else real_data_result = sum(abs(real(fft_data_com(start_Idx+1:start_Idx+NFFT)) - real_data_sim(start_Idx+1:start_Idx+NFFT))); imag_data_result = sum(abs(imag(fft_data_com(start_Idx+1:start_Idx+NFFT)) - imag_data_sim(start_Idx+1:start_Idx+NFFT))); end a = real_data_result + imag_data_result
从上面结果可以验证我们实验的正确性,从而说明MATLAB与VIVADO输出的数据完全相同,两者相互验证了实验的正确性。参考文献
总结
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算