Introduction
In this article, I will give a detailed introduction about how to design a FIR filter with Matlab R2022a and Vivado 2018.3. The reference video link is here.
Implementation
1. Using Matlab to generate the coefficients of the fir
Open Matlab and input fdatool in the command line and open the UI of designing a filter as is shown below.
and set the parameters as below, where at position 1, choose the type of the filter and 2 for the method to generate it. At 3, set the orders of the filter, and here we set it to be 99. At position 4 chooses the type of window function used, while at 5, set the unit of frequency to be MHz, and set sampling frequency to be 32MHz and cutoff frequency 1.5MHz.
Then we have to set the quantization of preserving the coefficients since when designing the FPGA using Vivado, it is hard to store a number with too much bits. Click on the 3rd icon in the leftmost column and set the quantization to be 16 bits so that it is much easier to preserve in FPGA. And the procedure is shown below.
At position 2, choose fixed point and then at position 3, set the quantization bits as 16. After that, export the coeffcient to .coe file which could be read by Xilinx Vivado by clicking target - Xilinx Coefficient (.coe).
After here, the design of the filter using Matlab is finished.
2. Using Vivado to do the Simulation
First create a new project and choose the FPGA used, here I’m using xc7z010clg400-1.
And then click on create block design to instantiated the IP core of FIR filter as shown below.
Double click on the IP core (position 1) and import the .coe file generated in step 1 as below.
And then switch to the second page of configuration by click 1 and set the frequency to be 32MHz as is previously set in Matlab.
After this, switch two the 3rd page of configuration as below, click on position 1 and set 2 and 3, as symmetric.
Then right click on the IP core and click Make External, then click validation design. Then open the resources and Generate Output Products and Create HDL Wrapper.
After that, create simulation file.
(1) Simulation Sources - sim_1->right click Add Sources;
(2) Add or Create Simulation Sources.
Then write the testbench file in Verilog.
`timescale 1ns / 1ps // unit: 1ns and accuracy 1ps
//
// Company:
// Engineer: He Shi
//
// Create Date: 2022/08/12 11:08:56
// Design Name:
// Module Name: fir_ip_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fir_ip_tb();
reg clk;
reg [15:0] data_in;
wire [39:0] data_out;
wire data_out_valid;
wire data_in_ready;
fir_design_wrapper U1_design_1_wrapper(
.M_AXIS_DATA_0_tdata(data_out),
.M_AXIS_DATA_0_tvalid(data_out_valid),
.S_AXIS_DATA_0_tdata(data_in),
.S_AXIS_DATA_0_tready(data_in_ready),
.S_AXIS_DATA_0_tvalid(1'b1),
.aclk_0(clk)
);
Generate Input Signal
(1) Input clk signal
// Generate 32MHz time signal for simulation
initial begin
clk=0;
end
always #16 clk=~clk;
(2) Input data waiting for simulation.
Here we use Matlab to generate simulation data.
%%% This code is write in Matlab
%% Generate data to be filtered after being quantized
%% and then write into .txt file
clear;clc;
% Initialization of varibles
f1=0.5; % freqeuency of signal 1 is 500kHz
f2=5; % freqeuency of signal 2 is 5MHz
Fs=32; % sampling frequency is 32MHz
N=16; % bits of quantization
% Generate the signal
t=0:1/Fs:5;
s1=sin(2*pi*f1*t); % sinusoidal wave 1
s2=sin(2*pi*f2*t); % sinusoidal wave 2
s=s1+s2; % combination of the 2 waves
s=s/max(abs(s));
% 16 bits quantization
Q_s=round(s*(2^(N-1)-1));
% write the generated data in decimal form into the Int_signal.txt file
fid=fopen(".\Int_signal.txt",'w');
fprintf(fid,"%16d\r\n",Q_s);
fprintf(fid,';');
fclose(fid);
temp=dec2bin(Q_s);
% write the generated data in binary form into the Bin_signal.txt file
fid=fopen(".\Bin_signal.txt",'w');
for i=1:1:length(Q_s)
for j=1:1:16
if temp(i,j)=='1'
fprintf(fid,"%d",1);
else
fprintf(fid,"%d",0);
end
end
fprintf(fid,"\r\n");
end
fprintf(fid,';');
fclose(fid);
And finally read the binary data into Vivado as the data waiting for simulation. Here we use stimulus to receive 64 numbers with 16 bits each and repeat for 30 times.
// read .txt file from outside
parameter data_num=64;
integer Pattern;
reg [15:0] stimulus[1:data_num];
initial begin
$readmemb("E:\\project\\Lab_project\\FPGA_study\\Part_1_Logic\\design_fir\\fir_design\\Bin_signal.txt",stimulus);
Pattern=0;
repeat(30) begin
repeat(data_num)begin
Pattern=Pattern+1;
data_in=stimulus[Pattern];
# 32;
end
Pattern=0;
end
#500;
$stop;
end
endmodule
After finish writing the testbench file, we can run the simulation as following. We can set the waveform style as following. First right click on the name of a signal and then choose analog as the waveform style.
and then we can continue simulation and see the result as shown below.
As is vividly depicted in the figure that, the signal 1, namely the input signal, is a 0.5MHz signal added with a 5MHz noise and signal 2 is the output signal after being filtered by the low-pass filter, the 5MHz noise is filtered out.