Several Digilent Forum Staff members will be out concurrently the week of August 5th. Responses may be delayed. ×
• 0

# The custom FIR filter IP is implemented in Verilog using DSP slices

## Question

Creating a custom IP to utilize digital slices in the FPGA for a digital filter involves designing an efficient filter implementation that leverages the DSP slices available in the Xilinx FPGA. Below, I'll provide step-by-step instructions on how to create a custom FIR filter IP in Vivado and integrate it with the Zynq-7000 processing system.

what i did

1. Create Custom FIR Filter IP in Vivado

Open Vivado and Create a New Project:

Open Vivado and create a new project.

Add the Zynq-7000 Processing System to block design.

Create a New AXI4 Peripheral:

From the IP Catalog, select Tools -> Create and Package New IP.

Choose Create a new AXI4 peripheral.

Add an AXI4-Lite interface for control and configuration.

Implement the FIR Filter:

Open the created custom IP and add a new Verilog module for the FIR filter.

Define the filter coefficients and implement the filter logic using DSP slices.

module fir_filter (
input wire clk,
input wire rst,
input wire [15:0] sample_in,
output wire [15:0] sample_out
);

parameter N = 5; // Number of filter coefficients
reg [15:0] shift_reg [0:N-1];
wire signed [15:0] coeff [0:N-1];
assign coeff[0] = 16'h0CCD; // Example coefficients
assign coeff[1] = 16'h199A;
assign coeff[2] = 16'h2000;
assign coeff[3] = 16'h199A;
assign coeff[4] = 16'h0CCD;

reg signed [31:0] acc;
integer i;

always @(posedge clk) begin
if (rst) begin
for (i = 0; i < N; i = i + 1) begin
shift_reg[i] <= 16'b0;
end
acc <= 32'b0;
end else begin
shift_reg[0] <= sample_in;
for (i = 1; i < N; i = i + 1) begin
shift_reg[i] <= shift_reg[i-1];
end
acc <= 0;
for (i = 0; i < N; i = i + 1) begin
acc <= acc + (shift_reg[i] * coeff[i]);
end
end
end

assign sample_out = acc[31:16]; // Output most significant 16 bits

endmodule

module fir_filter_ip_v1_0 #
(
parameter integer C_S_AXI_DATA_WIDTH = 32,
)
(
input wire clk,
input wire rst,
input wire s_axi_awvalid,
input wire [C_S_AXI_DATA_WIDTH-1:0] s_axi_wdata,
input wire [C_S_AXI_DATA_WIDTH/8-1:0] s_axi_wstrb,
input wire s_axi_wvalid,
output wire [1:0] s_axi_bresp,
output wire s_axi_bvalid,
input wire s_axi_arvalid,
output wire [C_S_AXI_DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rvalid,

input wire [15:0] sample_in,
output wire [15:0] sample_out
);

// Instantiate the FIR filter
fir_filter fir_filter_inst (
.clk(clk),
.rst(rst),
.sample_in(sample_in),
.sample_out(sample_out)
);

// AXI4-Lite interface logic (simplified)
// Add the necessary AXI4-Lite interface logic here

endmodule

how do i add those module in block digram

## Recommended Posts

• 0
17 minutes ago, amilashanaka said:

how do i add those module in block digram

Your packaged IP needs to be in an IP repository associated with the project to which you want to add it. If you created the IP with an existing project already open, it should already be there. If not, Settings -> IP -> Repository -> Plus Button -> Find and Select a folder containing your IP's files. This works the same as adding Digilent's vivado-library repository, if you've messed with that separately before.

Once that's done, you should be able to add it to the block design just like any other IP, with the Add IP button.

If instead of IP, these are just source files in your project, you could instead use the Add Module context menu option. It can infer some standard interfaces like AXI and bundle those ports, but has some quirks.

##### Share on other sites

• 0

Thanks Lot   idont have any idea where to connect sample in and out , can you help on that as well

Edited by amilashanaka
##### Share on other sites

• 0

The connections for those signals depend on the design. You could connect them to another IP block, or they could be signals going to the outside world. What exactly are you trying to do?

##### Share on other sites

• 0
4 hours ago, digility said:

The connections for those signals depend on the design. You could connect them to another IP block, or they could be signals going to the outside world. What exactly are you trying to do?

I want pass data coming from PMODAd1 through filter , im new to here not much experience how to do it

##### Share on other sites

• 0

I haven't used the Pmod AD1 before. However, I assume that a signal from the outside world is coming into the FPGA, passing through the FIR filter you've implemented within the FPGA, and then going out to the outside world.

Right-click on the sample_in and sample_out ports, select 'make external,' and then give them the same names in an XDC (constraint) file. In the XDC file, the pin name where you want to connect the input and output on the FPGA should match the name in the block diagram.

##### Share on other sites

• 0

By the way, if I remember correctly, the AXI protocol uses an active low reset. However, your design has an active high reset. This could cause an issue. Please correct me if I'm wrong. @artvvb

##### Share on other sites

• 0

Based on the code and block design that's been posted, currently data from the Pmod AD1 can come in through the Quad SPI IP core and then be read by the processor. You should confirm that this works, printing received data over serial would be sufficient. To get data into and out of the filter module, as it currently stands, you need a way to move data from the processor's memory to the filter. There's no data path from the processor to the FIR filter - the AXI interface in the custom IP you've created doesn't do anything (AXI signals aren't connected inside the IP, or are redacted). You could map the filter input and output signals to AXI-addressable registers and actually use the AXI interface, which is pretty complicated for beginners... Alternatively, you could connect the input and output ports of the module to a GPIO core. Software running in the processor would need to 1. read a piece of data from the QSPI, 2. write it to the GPIO or the filter's AXI interface, 3. read the result back from the filter, and 4. do something else with that data, probably print it. This is not the only way to do this design, only what I think is hopefully the fastest path to something that works on a board given your level of experience.

Regardless, I highly recommend running through a bunch of tutorials on the basics of what's going on in a Vivado project with a processor in it, and making sure you actually understand them. Digilent has this one on the site: https://digilent.com/reference/programmable-logic/guides/getting-started-with-ipi. You should do the same with a tutorial on AXI peripherals. This one looks good at a glance: https://www.hackster.io/pablotrujillojuan/designing-a-custom-axi-ip-on-vitis-a0ad06.

3 hours ago, digility said:

By the way, if I remember correctly, the AXI protocol uses an active low reset. However, your design has an active high reset. This could cause an issue. Please correct me if I'm wrong.

You're correct, and this will be a problem. Typically whether a reset is active low is indicated by the presence of the bubble on the reset input port, which you can see on the QSPI core. This is present on the filter IP, but that's a bug - based on the HDL source, "if (rst)", it's active high. When it's inferring port types, the IP packager doesn't interpret the port name rst as an active high reset for some reason. The easiest fix for @amilashanaka is likely to select the reset pin in the block diagram and change its POLARITY in the properties pane to ACTIVE_HIGH, disconnect the pin, and have Vivado do connection automation for it again. This is what changing that setting looks like (image not totally representative, it's a project I happened to have open):

If that doesn't work, the more correct way to do it would be to mark the port as an active high reset in the IP packager. The setting gets applied as a parameter for the port, in the Ports and Interfaces tab. Double clicking on the S00_AXI_RST interface in the screenshot below brings up the Edit Interface window, whose Parameters tab is the to change the polarity:

Thanks,

Arthur

##### Share on other sites

• 0
On 8/2/2024 at 8:50 PM, artvvb said:

Based on the code and block design that's been posted, currently data from the Pmod AD1 can come in through the Quad SPI IP core and then be read by the processor. You should confirm that this works, printing received data over serial would be sufficient. To get data into and out of the filter module, as it currently stands, you need a way to move data from the processor's memory to the filter. There's no data path from the processor to the FIR filter - the AXI interface in the custom IP you've created doesn't do anything (AXI signals aren't connected inside the IP, or are redacted). You could map the filter input and output signals to AXI-addressable registers and actually use the AXI interface, which is pretty complicated for beginners... Alternatively, you could connect the input and output ports of the module to a GPIO core. Software running in the processor would need to 1. read a piece of data from the QSPI, 2. write it to the GPIO or the filter's AXI interface, 3. read the result back from the filter, and 4. do something else with that data, probably print it. This is not the only way to do this design, only what I think is hopefully the fastest path to something that works on a board given your level of experience.

Regardless, I highly recommend running through a bunch of tutorials on the basics of what's going on in a Vivado project with a processor in it, and making sure you actually understand them. Digilent has this one on the site: https://digilent.com/reference/programmable-logic/guides/getting-started-with-ipi. You should do the same with a tutorial on AXI peripherals. This one looks good at a glance: https://www.hackster.io/pablotrujillojuan/designing-a-custom-axi-ip-on-vitis-a0ad06.

You're correct, and this will be a problem. Typically whether a reset is active low is indicated by the presence of the bubble on the reset input port, which you can see on the QSPI core. This is present on the filter IP, but that's a bug - based on the HDL source, "if (rst)", it's active high. When it's inferring port types, the IP packager doesn't interpret the port name rst as an active high reset for some reason. The easiest fix for @amilashanaka is likely to select the reset pin in the block diagram and change its POLARITY in the properties pane to ACTIVE_HIGH, disconnect the pin, and have Vivado do connection automation for it again. This is what changing that setting looks like (image not totally representative, it's a project I happened to have open):

If that doesn't work, the more correct way to do it would be to mark the port as an active high reset in the IP packager. The setting gets applied as a parameter for the port, in the Ports and Interfaces tab. Double clicking on the S00_AXI_RST interface in the screenshot below brings up the Edit Interface window, whose Parameters tab is the to change the polarity:

Thanks,

Arthur

Thank you , serial out put as follows

## Create an account

Register a new account