上文 FPGA數(shù)字信號處理之濾波器2_使用dsp48e1的fir濾波器設計完成了結構設計:
根據(jù)這一結構,假定要設計一個滿速率的fir濾波器,濾波器系數(shù)為:[3,13,27,58,62,204,47,546,233,1465,3260,3260,1465,233,546,47,204,62,58,27,13,3],濾波器總共22個系數(shù),對稱結構,所以有效系數(shù)11個。
以輸入數(shù)據(jù)為自加數(shù)為例,根據(jù)結構可以得到數(shù)據(jù)擺放格式如下,clk0時刻的計算公式為:(500+521)*c0+(501+520)*c1+......+(510+511)*c10;clk1時刻的計算公式為:(501+522)*c0+(502+521)*c1+......+(511+512)*c10;....
據(jù)此,設計fir代碼如下:
代碼設置三個參數(shù),數(shù)據(jù)位寬、系數(shù)個數(shù)、系數(shù)增益,其中系數(shù)個數(shù)決定代碼中乘法器的個數(shù)及代碼的處理時延,系數(shù)增益是系數(shù)給數(shù)據(jù)帶來的增益,在數(shù)據(jù)輸出的時候要通過截位截掉。
// ============================================================
// File Name: cm_fir_top
// VERSION : V1.0
// DATA : 2023/3/4
// Author : FPGA干貨分享
// ============================================================
// 功能:fir濾波器代碼
// coef =
// delay : 4+C_COEF_NUM*2
// ============================================================
`timescale 1ns/100ps
module cm_fir_top #(
parameter C_DATA_WIDTH = 16 ,
parameter C_COEF_NUM = 11 , ///有效系數(shù)個數(shù)
parameter C_COEF_CUT_NUM = 12 ) ///四舍五入使用的0.5大小
(
input wire I_sys_clk , /// 工作時鐘
input wire I_rst_in , /// 復位
input wire [C_DATA_WIDTH-1:0] I_data_in , /// 數(shù)據(jù)輸入
output reg [C_DATA_WIDTH-1:0] O_data_out /// 數(shù)據(jù)輸出
);
// ============================================================
// 內部參數(shù)
// ============================================================
localparam C_COEF_05 = 2**C_COEF_CUT_NUM ;
// ============================================================
// 變量
// ============================================================
reg [C_DATA_WIDTH-1:0] S_data_in[C_COEF_NUM*2-1:0] ;
wire [17:0] S_coef[C_COEF_NUM-1:0] ;
wire [47:0] S_pcout[C_COEF_NUM-1:0] ;
wire [47:0] S_dsp_out[C_COEF_NUM-1:0] ;
然后就是主代碼,使用assign給系數(shù)賦值,然后根據(jù)系數(shù)個數(shù)緩存輸入數(shù)據(jù),用于fir濾波器的卷積操作。隨后例化第一個dsp,U0_cm_dsp48e1,該濾波器作為級聯(lián)濾波器組的開頭乘法器,沒有級聯(lián)輸入,但是使用C端口作為假四舍五入預加的輸入,隨后使用generate根據(jù)濾波器系數(shù)個數(shù)生成級聯(lián)dsp組,最后將最后一級濾波器的輸出進行截位,得到最終結果。
// ============================================================
// main code
// ============================================================
assign S_coef[0 ] = 18'd3 ;
assign S_coef[1 ] = 18'd13 ;
assign S_coef[2 ] = -18'd27 ;
assign S_coef[3 ] = -18'd58 ;
assign S_coef[4 ] = 18'd62 ;
assign S_coef[5 ] = 18'd204 ;
assign S_coef[6 ] = -18'd47 ;
assign S_coef[7 ] = -18'd546 ;
assign S_coef[8 ] = -18'd233 ;
assign S_coef[9 ] = 18'd1465 ;
assign S_coef[10] = 18'd3260 ;
always@(posedge I_sys_clk)
S_data_in[0] <= I_data_in ;
genvar i;
generate for(i=1;i< C_COEF_NUM*2;i=i+1)
begin
always@(posedge I_sys_clk)
S_data_in[i] <= S_data_in[i-1];
end
endgenerate
cm_dsp48e1 #(
.C_DATA_WITH_A (C_DATA_WIDTH ),
.C_DATA_WITH_B (18 ),
.C_DATA_WITH_C (32 ),
.C_DATA_WITH_D (C_DATA_WIDTH )
)
U0_cm_dsp48e1(
.I_CLK (I_sys_clk ) , // clk
.I_RST (I_rst_in ) , // RST
.I_A (S_data_in[0] ) , // [29:0]
.I_B (S_coef[0 ] ) , // [17:0]
.I_C (C_COEF_05 ) , // [47:0]
.I_D (S_data_in[C_COEF_NUM*2-1] ) , // [24:0]
.I_PCIN (48'd0 ) , // [47:0] 只能直連PCOUT
.I_ALUMODE (4'd0 ) , // [3:0]
.I_INMODE (5'b00101 ) , // [4:0]
.I_OPMODE (7'b0110101 ) , // [6:0] C + (A+D)*B
.O_P ( ) , // [47:0]
.O_PCOUT (S_pcout[0] ) // [47:0] 只能直連PCIN
);
genvar j;
generate for(j=1;j< C_COEF_NUM;j=j+1)
begin
cm_dsp48e1 #(
.C_DATA_WITH_A (C_DATA_WIDTH ),
.C_DATA_WITH_B (18 ),
.C_DATA_WITH_C (32 ),
.C_DATA_WITH_D (C_DATA_WIDTH )
)
U1_cm_dsp48e1(
.I_CLK (I_sys_clk ) , // clk
.I_RST (I_rst_in ) , // RST
.I_A (S_data_in[2*j] ) , // [29:0]
.I_B (S_coef[j ] ) , // [17:0]
.I_C (32'd0 ) , // [47:0]
.I_D (S_data_in[C_COEF_NUM*2-1] ) , // [24:0]
.I_PCIN (S_pcout[j-1] ) , // [47:0] 只能直連PCOUT
.I_ALUMODE (4'd0 ) , // [3:0]
.I_INMODE (5'b00101 ) , // [4:0]
.I_OPMODE (7'b0010101 ) , // [6:0] PCin + (A+D)*B
.O_P (S_dsp_out[j] ) , // [47:0]
.O_PCOUT (S_pcout[j] ) // [47:0] 只能直連PCIN
);
end
endgenerate
always@(posedge I_sys_clk)
O_data_out <= S_dsp_out[C_COEF_NUM-1][C_COEF_CUT_NUM+1+:C_DATA_WIDTH] ;
endmodule