Xilinx FIR compiler IP 实现可重加载滤波系数的低通滤波器

参考文档:pg149-fir-compiler

一、FIR compiler IP配置

        详细的可参考IP核的用户手册,此处主要记录一下使用过程中不太理解的地方。

1、滤波器系数保存方式有两种,Vector和COE FILE。其中注意的是Vector中输入的是十进制数。COE文件按照标准格式保存即可。

 本文中使用的是COE文件,主要是方便matlab可以直接生成COE文件。

另外,本文使用了勾选了use reloadabel coefficients,可重新配置滤波器系数。

2、通道配置,此处没有需要特别介绍的,按照需要勾选即可。

 3、实现方式上,滤波器系数均采用无符号数据,输入数据也为无符号数据,这样就可以得到无符号的滤波后数据。在左侧可以看到目前设置下数据的延时、滤波器系数和输出数据的类型与位宽、重新加载时的滤波器系数配置顺序。

 4、滤波器架构选择转置滤波器,选择它的原因我所做的项目需要较少的数据延时。

 5、最后是数据的接口,忽略了AXIS总线的LAST信号,使能了复位信号。按需勾选即可。

 二、逻辑程序的编写与仿真

2.1 模拟源生成

此处使用了DDS complier IP 模拟生成正弦波。DDS IP生成了9.3M左右的正弦波,配置截图如下:

 

 

 此处有一个问题需要注意,DDS IP输出的为有符号数,而我们前面设置的FIR输入数据为无符号数。实际观察结果的时候,我们将DDS输出的波形按照无符号数波形进行观察。

2.2 逻辑代码实现

FIR IP核控制模块如下:

`timescale 1ns / 1ps


module FIR_8_order(
    input clk_300M, //300M时钟
    input [15:0] FIR_coe0,//滤波器系数0
    input [15:0] FIR_coe1,//滤波器系数1
    input [15:0] FIR_coe2,//滤波器系数2
    input [15:0] FIR_coe3,//滤波器系数3
    input [15:0] FIR_coe4,//滤波器系数4
    input [15:0] FIR_coe5,//C滤波器系数5
    input [15:0] FIR_coe6,//滤波器系数6
    input [15:0] FIR_coe7,//滤波器系数7
    input [15:0] FIR_coe8,//滤波器系数8
    
    input FIR_en,//CH1滤波器使能
    input FIR_coe_update,//更新滤波器参数

    input [15:0] data_in,//波形数据
    input data_valid,
    
    input data_end,//滤波结束标志
    
    output reg [15:0] fir_data_out //滤波后数据输出
    );

//-----------------------------信号定义-------------------------

(*mark_debug = "TRUE"*)reg [3:0]state; //状态机   
reg [3:0]next_state; //状态机   
localparam IDLE_STATE = 4'b0001; //空闲状态
localparam RELOAD_STATE = 4'b0010;//重加载状态
localparam DELAY_STATE = 4'b0100;//配置状态
localparam CONFIG_STATE = 4'b1000;//配置状态

//FIR滤波器输入数据    
//wire s_axis_data_tvalid;
//wire s_axis_data_tready;
//wire [15:0] s_axis_data_tdata;
//FIR滤波器config数据  
(*mark_debug = "TRUE"*)reg s_axis_config_tvalid;
(*mark_debug = "TRUE"*)wire s_axis_config_tready;
(*mark_debug = "TRUE"*)wire [7:0] s_axis_config_tdata;
//FIR滤波器reload数据  
(*mark_debug = "TRUE"*)reg s_axis_reload_tvalid;
(*mark_debug = "TRUE"*)wire s_axis_reload_tlast;
(*mark_debug = "TRUE"*)wire s_axis_reload_tready;
(*mark_debug = "TRUE"*)reg [15:0] s_axis_reload_tdata;

//FIR滤波器输出数据  
//wire m_axis_data_tvalid;
wire [39:0] m_axis_data_tdata;
//FIR滤波器标志数据  
(*mark_debug = "TRUE"*)wire event_s_reload_tlast_missing;
(*mark_debug = "TRUE"*)wire event_s_reload_tlast_unexpected  ; 
    
reg fir_rstn;//滤波器复位标志

reg FIR_coe_update_d1;//FIR_coe_update同步信号
reg FIR_coe_update_d2;//FIR_coe_update同步信号
reg FIR_coe_update_pulse; //FIR_coe_update上升沿脉冲,有效2个时钟

reg [3:0] reload_cnt;//加载滤波器系数计数
localparam COE_NUM = 4'd9; //滤波器系数为9个
reg [1:0]config_cnt;//配置计数
reg reload_cmp;//加载滤波器系数完成
reg config_cmp;//配置滤波器完成


reg delay_cmp; //延时完成
reg [3:0] delay_cnt;//延时16个时钟

//-----------------------------逻辑实现-------------------------
//--------------------------------------------------------------
always@(posedge clk_300M)
begin
    if(FIR_en) //滤波使能
        fir_rstn <= !data_end;//读取完一整帧时,将FIR复位等待下次滤波
    else
        fir_rstn <= 1'b0;//不开启滤波器时,将IP核复位
end


always@(posedge clk_300M)
begin
    FIR_coe_update_d1 <= FIR_coe_update;//延迟1个时钟
    FIR_coe_update_d2 <= FIR_coe_update_d1;//延迟1个时钟
    FIR_coe_update_pulse <= !FIR_coe_update_d2 & FIR_coe_update;//FIR_coe_update上升沿脉冲,有效2个时钟
end


//状态机控制
always@(posedge clk_300M)
begin
    state <= next_state;
end


always@( * )
begin
    case(state)
        IDLE_STATE : begin
            if(FIR_coe_update_pulse) //接收到ARM下发的更新FIR系数指令
                next_state <= RELOAD_STATE;
            else
                next_state <= IDLE_STATE;
        end
        RELOAD_STATE : begin
            if(reload_cmp) //加载完毕9个FIR系数,跳转状态机
                next_state <= DELAY_STATE;
            else
                next_state <= RELOAD_STATE;
        end
        
        DELAY_STATE : begin
            if(delay_cmp) //加载完毕9个FIR系数,跳转状态机
                next_state <= CONFIG_STATE;
            else
                next_state <= DELAY_STATE;
        end
        
        
        CONFIG_STATE : begin
            if(config_cmp) //配置完FIR
                next_state <= IDLE_STATE;
            else
                next_state <= CONFIG_STATE;
        end
        default:next_state <= IDLE_STATE;
    endcase
end


//各状态下下的操作----------------------

//RELOAD_STATE状态

always@(posedge clk_300M)
begin
    if(state == RELOAD_STATE) begin
        if(s_axis_reload_tvalid & s_axis_reload_tready) //每写入1次滤波器系数,reload_cnt加1
            reload_cnt <= reload_cnt + 1;
    end
    else begin //其余状态加清零
        reload_cnt <= 0;
    end
end
//加载最后一个滤波器系数
assign s_axis_reload_tlast = (reload_cnt == COE_NUM -1) & s_axis_reload_tready & s_axis_reload_tvalid;
always@(posedge clk_300M)
begin
    if(state == RELOAD_STATE) begin
        if(reload_cnt < COE_NUM -1)  //加载滤波器系数
            s_axis_reload_tvalid <= 1'b1;
        else if((reload_cnt == COE_NUM -1) && s_axis_reload_tready) //加载最后一个滤波器系数
            s_axis_reload_tvalid <= 1'b0;
    end
    else begin
        s_axis_reload_tvalid <= 1'b0;
    end
end


always@(posedge clk_300M)
begin
    s_axis_reload_tdata <= FIR_coe0; //默认输出寄存器系数0
    if(s_axis_reload_tvalid & s_axis_reload_tready) begin //每写入1次滤波器系数,reload_cnt加1
        case(reload_cnt)
            'd0:s_axis_reload_tdata <=FIR_coe1;//写完第0个滤波器系数,立刻更新新的滤波器系数
            'd1:s_axis_reload_tdata <=FIR_coe2;//写完第1个滤波器系数,立刻更新新的滤波器系数
            'd2:s_axis_reload_tdata <=FIR_coe3;//写完第2个滤波器系数,立刻更新新的滤波器系数
            'd3:s_axis_reload_tdata <=FIR_coe4;//写完第3个滤波器系数,立刻更新新的滤波器系数
            'd4:s_axis_reload_tdata <=FIR_coe5;//写完第4个滤波器系数,立刻更新新的滤波器系数
            'd5:s_axis_reload_tdata <=FIR_coe6;//写完第5个滤波器系数,立刻更新新的滤波器系数
            'd6:s_axis_reload_tdata <=FIR_coe7;//写完第6个滤波器系数,立刻更新新的滤波器系数
            'd7:s_axis_reload_tdata <=FIR_coe8;//写完第7个滤波器系数,立刻更新新的滤波器系数

            default:;
        endcase
    end
end

always@(posedge clk_300M)
begin
    if((reload_cnt == COE_NUM -1) & s_axis_reload_tready & s_axis_reload_tvalid) //加载完滤波器系数时,reload_cmp有效
        reload_cmp <= 1'b1;
    else
        reload_cmp <= 1'b0;
end
     
DELAY_STATE状态
always@(posedge clk_300M) 
begin
    if(state == DELAY_STATE) //延时计数
        delay_cnt <= delay_cnt + 1;
    else
        delay_cnt <= 0;
end

always@(posedge clk_300M) 
begin
    delay_cmp <= delay_cnt[3];//延时完成
end

 
//CONFIG_STATE状态
assign s_axis_config_tdata = 0;

always@(posedge clk_300M)
begin
    if(state == CONFIG_STATE) begin
        if(s_axis_config_tvalid & s_axis_config_tready)
            config_cnt <= config_cnt +1;
    end
    else    
        config_cnt <= 0;
end

always@(posedge clk_300M)
begin
    if(config_cnt == 2'b10)
        config_cmp <= 1;
    else
        config_cmp <= 0; 
end


always@(posedge clk_300M)
begin
    if(state == CONFIG_STATE) begin
        if(config_cnt < 2'b01) 
            s_axis_config_tvalid <= 1'b1; 
        else if(s_axis_config_tvalid & s_axis_config_tready) 
            s_axis_config_tvalid <= 1'b0; 
    end
    else begin
        s_axis_config_tvalid <= 1'b0;
    end
end

fir_compiler_0 fir_compiler_0 (
  .aresetn(fir_rstn),                                                  // input wire aresetn
  .aclk(clk_300M),                                                        // input wire aclk
  .s_axis_data_tvalid(data_valid),                            // input wire s_axis_data_tvalid
  .s_axis_data_tready(),                            // output wire s_axis_data_tready
  .s_axis_data_tdata(data_in),                              // input wire [15 : 0] s_axis_data_tdata
  .s_axis_config_tvalid(s_axis_config_tvalid),                        // input wire s_axis_config_tvalid
  .s_axis_config_tready(s_axis_config_tready),                        // output wire s_axis_config_tready
  .s_axis_config_tdata(s_axis_config_tdata),                          // input wire [7 : 0] s_axis_config_tdata
  .s_axis_reload_tvalid(s_axis_reload_tvalid),                        // input wire s_axis_reload_tvalid
  .s_axis_reload_tready(s_axis_reload_tready),                        // output wire s_axis_reload_tready
  .s_axis_reload_tlast(s_axis_reload_tlast),                          // input wire s_axis_reload_tlast
  .s_axis_reload_tdata(s_axis_reload_tdata),                          // input wire [15 : 0] s_axis_reload_tdata
  .m_axis_data_tvalid(),                            // output wire m_axis_data_tvalid
  .m_axis_data_tdata(m_axis_data_tdata),                              // output wire [39 : 0] m_axis_data_tdata
  .event_s_reload_tlast_missing(event_s_reload_tlast_missing),        // output wire event_s_reload_tlast_missing
  .event_s_reload_tlast_unexpected(event_s_reload_tlast_unexpected)  // output wire event_s_reload_tlast_unexpected
);
 
always@(posedge clk_300M) 
begin
    if(FIR_en) //滤波器使能,输出数据为FIR数据
        fir_data_out<= m_axis_data_tdata[31:16]; //取有效数据的高16bits
     else //滤波器禁能
        fir_data_out<= data_in;
end











endmodule

仿真顶层程序

`timescale 1ns / 1ps
//

module testbench(

    );
   
reg clk_300M = 0;
always
begin
    #1.66 
    clk_300M <= ~clk_300M;
end
   
   
   
    
wire [15:0] data_in;//波形数据
wire data_valid;//有效标志

localparam [15:0] CH1_FIR_coe0 = 16'h02ff;//CH1滤波器系数0
localparam [15:0] CH1_FIR_coe1 = 16'h0a40;//CH1滤波器系数1
localparam [15:0] CH1_FIR_coe2 = 16'h1e37;//CH1滤波器系数2
localparam [15:0] CH1_FIR_coe3 = 16'h3500;//CH1滤波器系数3
localparam [15:0] CH1_FIR_coe4 = 16'h3f14;//CH1滤波器系数4
localparam [15:0] CH1_FIR_coe5 = 16'h3500;//CH1滤波器系数5
localparam [15:0] CH1_FIR_coe6 = 16'h1e37;//CH1滤波器系数6
localparam [15:0] CH1_FIR_coe7 = 16'h0a40;//CH1滤波器系数7
localparam [15:0] CH1_FIR_coe8 = 16'h02ff;//CH1滤波器系数8



reg FIR_coe_update=0;
reg data_end=0;
reg [9:0] rd_cnt=0;
reg [12:0] update_cnt=0;

always@(posedge clk_300M)
begin
    if(rd_cnt <= 10'h3FF)
        rd_cnt <= rd_cnt + 1;
end

always@(posedge clk_300M)
begin
    update_cnt <= update_cnt + 1;
end

always@(posedge clk_300M)
begin
    if(rd_cnt >= 10'h3FC)
        data_end <= 1'b1;
    else
        data_end <= 1'b0;
end

always@(posedge clk_300M)
begin
    if(update_cnt >= 13'h1FFC)
        FIR_coe_update <= 1'b1;
    else
        FIR_coe_update <= 1'b0;
end



dds_compiler_0 dds_compiler_0 (
  .aclk(clk_300M),                              // input wire aclk
  .m_axis_data_tvalid(data_valid),  // output wire m_axis_data_tvalid
  .m_axis_data_tdata(data_in)    // output wire [15 : 0] m_axis_data_tdata
);

    
FIR_8_order FIR_8_order_CH1(
    .clk_300M(clk_300M),//input clk_300M, //300M时钟
    .FIR_coe0(CH1_FIR_coe0),//input [15:0] FIR_coe0,//滤波器系数0
    .FIR_coe1(CH1_FIR_coe1),//input [15:0] FIR_coe1,//滤波器系数1
    .FIR_coe2(CH1_FIR_coe2),//input [15:0] FIR_coe2,//滤波器系数2
    .FIR_coe3(CH1_FIR_coe3),//input [15:0] FIR_coe3,//滤波器系数3
    .FIR_coe4(CH1_FIR_coe4),//input [15:0] FIR_coe4,//滤波器系数4
    .FIR_coe5(CH1_FIR_coe5),//input [15:0] FIR_coe5,//C滤波器系数5
    .FIR_coe6(CH1_FIR_coe6),//input [15:0] FIR_coe6,//滤波器系数6
    .FIR_coe7(CH1_FIR_coe7),//input [15:0] FIR_coe7,//滤波器系数7
    .FIR_coe8(CH1_FIR_coe8),//input [15:0] FIR_coe8,//滤波器系数8
    
    .FIR_en(1'b1),//input FIR_en,//CH1滤波器使能
    .FIR_coe_update(FIR_coe_update),//input FIR_coe_update,//更新滤波器参数

    .data_in(data_in),//input [15:0] compress_data,//波形数据
    .data_valid(data_valid),//input compress_data_valid,//数据有效标志
    
    .data_end(data_end),//input rd_dso_data_end,//波形结束标志
    
    .fir_data_out()//output [15:0] fir_data_out //滤波后数据输出
    );


endmodule

输入的波形和滤波后的波形对比如下,对9Mhz波形滤波后的波形与输入的波形差别不大,满足设计要求。

 需要注意的是,输出波形数据需要按照设计需求截取位宽,否则会导致波形幅度不正确。(16位无符号的滤波器系数,相加之后最大值约为16‘hFFFF,乘上16bits位宽的无符号数据后,输出数据位宽为32bits,截取高16bits输出)

 三、FIR 系数重加载介绍

 最后再说一下参数重加载的过程,按照手册要求时序图如下:

在这个过程中,需要注意的是,通过RELOAD通道配置完滤波器系数后,需要再通过配置CONFIG通道 连续有效两次s_axis_config_tvalid,以完成滤波器系数的更新。因为本次设计中只使用了1组滤波器系数,因此s_axis_config_tdata默认输出0x00即可。

问题:再调试过程中,在RELOAD通道配置完滤波器系数后,立刻在CONFIG通道有效两次s_axis_config_tvalid,希望能够完成滤波器系数的更新。但是造成RELOAD通道的s_axis_reload_tready信号拉低后无法拉高,RELOAD通道阻塞了。导致滤波器系数没有得到更新,并且后续也无法配置新的滤波器系数。

解决方式:后来各种更改程序,在RELOAD通道配置完滤波器系数后,延迟了几个时钟后再在CONFIG通道有效两次s_axis_config_tvalid,滤波器系数正常配置。

这样修改也符合用户手册中提供的接口时序。

  • 8
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值