上文 FPGA數字信號處理之濾波器2_使用dsp48e1的fir濾波器設計完成了結構設計:
根據這一結構,假定要設計一個滿速率的fir濾波器,濾波器系數為:[3,13,27,58,62,204,47,546,233,1465,3260,3260,1465,233,546,47,204,62,58,27,13,3],濾波器總共22個系數,對稱結構,所以有效系數11個。
以輸入數據為自加數為例,根據結構可以得到數據擺放格式如下,clk0時刻的計算公式為:(500+521)*c0+(501+520)*c1+......+(510+511)*c10;clk1時刻的計算公式為:(501+522)*c0+(502+521)*c1+......+(511+512)*c10;....
據此,設計fir代碼如下:
代碼設置三個參數,數據位寬、系數個數、系數增益,其中系數個數決定代碼中乘法器的個數及代碼的處理時延,系數增益是系數給數據帶來的增益,在數據輸出的時候要通過截位截掉。
// ============================================================
// 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 , ///有效系數個數
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 , /// 數據輸入
output reg [C_DATA_WIDTH-1:0] O_data_out /// 數據輸出
);
// ============================================================
// 內部參數
// ============================================================
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給系數賦值,然后根據系數個數緩存輸入數據,用于fir濾波器的卷積操作。隨后例化第一個dsp,U0_cm_dsp48e1,該濾波器作為級聯濾波器組的開頭乘法器,沒有級聯輸入,但是使用C端口作為假四舍五入預加的輸入,隨后使用generate根據濾波器系數個數生成級聯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