1
上文 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