FIR with FPGA[1].全并行FIR实现

来源:互联网 发布:淘宝二手手机店铺推荐 编辑:程序博客网 时间:2024/06/05 20:02

FIR with FPGA[0]中,使用Matlab环境对FIR进行了仿真,确定了输入数据和滤波器系数的量化bit和字长。下面将在FPGA中对FIR做实现。

FPGA中采用直接型


按照原理图进行RTL的构造,中间计算过程不作截位处理。

由于FPGA的时钟频率往往远远高于数据输入速率,MAC可以采用时分复用,以减轻资源消耗;设计者也可以利用系数的对称性减少乘法器的使用。但本例并不作此类优化。相关代码优化将在后续文章中展开。本文采用全并行结构,即多个乘法器同时工作。

本例设计中,数据输入速率等于FPGA工作频率。整个系统只有一个主时钟,不存在跨时钟域。


1. 模块组成

系统组成比较简单,如之前大图所示。输入16位数据,和start的指示信号。输入信号由testbench产生。系统所产生的输出,也由testbench导出到txt文件中。并由matlab读取后,验证误差值。


2. 源代码

通过modelsim仿真后,观察波形可知,FIR成功的滤除了高频分量。



FIR代码如下:

module FIR(input clk,input rst_n,input start,input [15:0] data_in,output reg finish,output reg signed [31:0] data_out);parameter IDLE = 2'b00, BUSY = 2'b01;parameter END = 16'd44100;wire signed [15:0] coef [0:16];assign coef[0]  = -17;   assign  coef[1]  = 62;    assign  coef[2]  = 456;assign coef[3]  = 1482;  assign  coef[4]  = 3367;  assign  coef[5]  = 6013;assign coef[6]  = 8880;  assign  coef[7]  = 11129; assign  coef[8]  = 11983;assign coef[9]  = 11129; assign  coef[10] = 8880;  assign  coef[11] = 6013;assign coef[12] = 3367;  assign  coef[13] = 1482;  assign  coef[14] = 456;assign coef[15] = 62;    assign  coef[16] = -17;// sync rst_nreg [1:0] rstn;always@(posedge clk or negedge rst_n)beginif(!rst_n) beginrstn <= 2'b0;endelse beginrstn[0] <= rst_n;rstn[1] <= rstn[0];endend//sync and delay data_inreg signed [15:0] data_buffer;always@(posedge clk or negedge rst_n)beginif(!rstn[1])begindata_buffer <= 16'd0;endelse begindata_buffer <= data_in;endend//FSMreg [1:0] state_pr, state_nx;always@(posedge clk or negedge rstn[1])beginif(!rstn[1])beginstate_pr <= IDLE;endelse beginstate_pr <= state_nx;endendreg [15:0] cnt;always@(*)beginif(!rstn[1])beginstate_nx = IDLE;endelse begincase(state_pr)IDLE:if(start == 1'b1)state_nx = BUSY;elsestate_nx = IDLE;BUSY:if(cnt == END - 1)begin  //44100 datastate_nx = IDLE;endelsestate_nx = BUSY;default:state_nx = IDLE;endcaseendend// caculate 44100 cyclesalways@(posedge clk or negedge rstn[1])beginif(!rstn[1])begincnt <= 16'd0;endelse if(state_pr == BUSY) begincnt <= cnt + 1'b1;endelse begincnt <= 16'd0;endend//44100th cycle, pull up finishalways@(posedge clk or negedge rstn[1])beginif(!rstn[1])beginfinish <= 1'b0;endelse if(cnt == END - 1) beginfinish <= 1'b1;endelse beginfinish <= 1'b0;endend//busy state buffer input datareg signed [16:0] delay [0:15];integer i; always@(posedge clk or negedge rstn[1])beginif(!rstn[1])beginfor(i=0;i<16;i=i+1)begindelay[i] <= 0;endendelse if(state_pr == BUSY) beginfor(i=0;i<16;i=i+1) beginif(i == 0)begindelay[i] <= data_buffer;endelse begindelay[i] <= delay[i-1];endendendend//17 multiplyreg signed [31:0] mac [0:16];always@(*)beginif(!rstn[1])beginfor(i=0;i<17;i=i+1)beginmac[i] = 31'd0;endendelsefor(i=0;i<17;i=i+1)beginif(i == 0) beginmac[i] = coef[0] * data_buffer;endelse beginmac[i] = coef[i] * delay[i-1];endendend//cumulative sumwire signed [31:0] sum = mac[0] + mac[1] + mac[2] + mac[3] + mac[4] +  mac[5] + mac[6] + mac[7] + mac[8] + mac[9] +     mac[10] + mac[11] + mac[12] + mac[13] + mac[14] +  mac[15] + mac[16] ; //sync outputalways@(posedge clk or negedge rstn[1])beginif(!rstn[1])begindata_out <= 32'd0;endelse begindata_out = sum;endend //delay finishalways@(posedge clk or negedge rstn[1])beginif(!rstn[1])beginfinish <= 1'b0;endelse beginif(state_pr == BUSY) beginfinish <= 1'b1;endelse beginfinish <= 1'b0;endendendendmodule

需要注意的是,verilog中readmemb只能读取二进制的数据,所以matlab需要事先将激励输入的数据转成二进制补码形式,存入到txt文件中。matlab中的代码如下:

%transform to 2'csignal_com = dec2bin( signal_scale +  2^16*(signal_scale<0) ,16);signal_com = signal_com.';fid = fopen('.\dataIn.txt','wb');for num = 1:44100    for i=1:16        fprintf(fid,'%s',signal_com( (num-1)*16 + i));    end    fprintf(fid,'\r\n');endfclose(fid);


以下是testbench中的代码

`timescale 1ns/1nsmodule TB_FIR;parameter PERIOD = 20;reg clk, rst_n, start;reg [15:0] data_in;wire finish;wire signed [31:0] data_out;FIR uut(.clk(clk),.rst_n(rst_n),.start(start),.data_in(data_in),.finish(finish),.data_out(data_out));initial beginclk = 0;rst_n = 0;#1000;rst_n = 1;endalways #(PERIOD/2) clk = ~clk;reg signed [15:0] mem [0:44399];initial begin$readmemb("F:/project/FIR/matlab/dataIn.txt",mem);end// 100~44399+100reg [15:0] cnt;always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt <= 1'b0;endelse beginif(cnt == 16'd44100 + 100)cnt <= cnt;elsecnt <= cnt + 1;endend// input start for 1clkalways@(posedge clk)beginif( cnt == 100)beginstart <= 1'b1;endelse beginstart <= 1'b0;endend// input dataalways@(posedge clk)beginif( cnt >= 100 && cnt <= 44399+100)begindata_in <= mem[cnt-100];endelse begindata_in <= 16'd0;endend// write output data to txt fileinteger file;initial beginfile = $fopen("../data_out.txt","w");endalways@(posedge clk)beginif(finish == 1'b1)begin$fdisplay(file,"%-d",data_out);endendendmodule 


将testbench生成的txt文件读入相对比较简单,matlab中只需一行textread就可以实现。

fpga_data = textread('..\data_out.txt');



0 0
原创粉丝点击