2.1: Creating the Design in Vivado Design Suite
This chapter is going to be devoted entirely to how we build the design in Vivado Design Suite that will allow us to feed data from the ARM processor on the Zynq 7010 to the FPGA. For more detail on creating a project in Vivado Design Suite, see my earlier tutorial on flashing an LED on the Virtex 7.
If you haven't already generated the GetCentroid IP, which was described in Chapter 1, make sure you do that. If you have, the steps you need to complete are as follows:
1) Open Vivado Design Suite. I'm using the 2016.4 version. If you're using a slightly different version, the menu items/prompts may be slightly different.
2) Create a new project. I called mine "GetCentroidDesign" since I called the HLS project "GetCentroid", but you can name yours whatever you'd like.
Select RTL project and do not specify sources at this time.
On the next screen, select "Boards" and then choose the MicroZed 7010 board. If the MicroZed 7010 doesn't show up in your list of boards, you may have to import the board definition file manually. To do this, go to:
to obtain the board definition files. Then you'll have to place the directory microzed_7010 in the directory C:\Xilinx\Vivado\[Version Number]\data\boards\board_files\. Once you do that, you should see it pop up as an option as in the shot below.
When you're finished, the last dialog box should look like this:
3) Add your GetCentroid IP to the IP Repository. We need to point Vivado to the IP we just created. Go to Tools -> Project Settings -> IP -> Repository Manager . Click the "+" icon and select the directory that holds the GetCentroi IP repository you just created with HLS. After you do this, you should see it pop up in the following window.
4) Create a block design. On the left panel of the Design Suite GUI, click on Create Block Design under the IP Integrator. You can name your design whatever you want, I tend to give mine the same name as the project name.
5) Add the Zynq 7 Processor. Click Add IP, and select "ZYNQ 7 Processing System". You can make it easier by typing "Zynq" into the search bar and Vivado should pull it up for you.
5a) Click on the Run block automation link that shows up at the top of the block design. Keep all the options at their defaults and select "OK".
5b) Double-click on the Zynq block, select PS-PL Configuration, and check the box: AXI Non-Secure Enrollment -> GP Master AXI Interface -> M AXI GPO Interface.
5c) Check HP Slave AXI Interface -> S AXI HP0 interface. The box should look like this:
5d) Go to Clock Configuration and check the box PL Fabric Clocks -> FCLK_CLK0. If you kept the clock period at 10ns when you were synthesizing GetCentroid in HLS, you can keep the Requested Frequency at 100 MHz. If you changed the clock period, you will have to adjust the clock frequency here accordingly (the Requested Frequency should be the reciprocal of the Clock Period). This PLL is going to be generating the clock that goes into our IP, so if there is a mismatch from the frequency it expects, we could have problems.
5e) Connect FCLK_CLK0 to M_AXI_GP0_ACLK on the block diagram using whatever technique you prefer (I usually right-click on one of the input and select "Make Connection"). Your diagram should then look like so:
6) Add the GetCentroid IP. Click Add IP and select GetCentroid (again, you can search for it in the search bar and it should pop up). You should see your GetCentroid module pop up. Any of those inputs and outputs look familiar? The inStream should. That's our HLS Stream that we're feeding into our algorithm. The s_axi_CTRL_BUS will contain the other parameters we're passing.
6a) Run connection automation by clicking the blue link at the top of the GUI. Keep all the options at their default and press OK. You should see Processor System Reset and AXI Interconnect blocks pop up like so:
Notice how Vivado nicely makes all the necessary clock and reset connections for you; quite a nice feature. It also sets up the DDR RAM and the IO from the processor block.
7) Add and configure the DMA Engine. Click Add IP and select AXI Direct Memory Access. Once it pops up on the block diagram, double click the block so we can configure it. We'll do the following configuration options:
7a) Uncheck "Enable Scatter Gather Engine". For simplicity, we are only going to do a single pulse each time we request a DMA transfer. If you have an idea in mind where you're going to have to DMA a lot of data from memory to your algorithm (for instance, if you had a large image, and you needed to run each row of the image through the algorithm), you may want to look into Scatter-Gather transfers. It will allow you to set up a large transfer that requires minimal intervention.
7b) Uncheck "Enable Write Channel". We are not going to DMA our output data back to memory like you'll see in many other examples. Again, this is because the result of our algorithm is just a single number instead of a stream that's sized equally to the input. There are lots of tutorials out there where an HLS stream is returned by the IP. I particularly like this one.
7c) Set the Max Burst Size to 256 on the read channel.
7d) Set Width of Buffer Length Register to 23 bits.
7e) Click on "Allow Unaligned Transfers" on read channel. After this, your menu should look like this:
8) Connect your DMA Engine to everything else. In order to connect things with the least amount of interventino necessary, we're going to do this in two steps.
8a) Click on Run Connection Automation. This time, only select axi_dma_0 and click OK.
8b) Click on Run Connection Automation again. Now select the S_AXI_HP0 port and connect it to DMA M_AXI_MM2S. Keep the Clock Connection dropdown on "Auto".
8c) Connect the inStream of the HLS module to M_AXIS_MM2S. The simplest way to do this, in my opinion, is to right-click on the inStream input of the GetCentroid block and select Make Connection. You can then just double click on M_AXIS_MM2S. Now your block diagram should look like this:
9) Enable interrupts to the processor. Double click on ZYNQ and select Interrupts on the left hand column of the window that pops up. Enable Fabric Interrupts by clicking that box, and then select PL-PS interrupts and select IRQ_F2P[15:0] like so:
10) Concatenate and connect the interrupts. Click Add IP and select Concat. This will add the Concatenation IP to your design.
10a) Connect the interrupt from the GetCentroid block to In0 of the Concat block. This will allow us to generate an interrupt when a centroid has been calculated.
10b) Connect the mm2s_introut output on the DMA block to In1 of the he Concat block. This will allow us to generate an interrupt when the DMA transfer has completed.
10c) Connect the output of the concat module to the IRQ_F2P input of the ZYNQ.
11) Regenerate the layout. Your design may look pretty ugly right now. You can usually solve this by clicking on the "Regenerate Layout" icon (the circular arrows) to clean it up. Here is what my design looks like after adding and connecting everything
Yours may look slightly different. That's ok. Just make sure all the connections match up.
12) Validate the design. Right-Click on the design and select "Validate Design". If you did everything correctly, you should get a message telling you that you were successful. If not, go back and check that you followed all the steps exactly. You may have to manually make a connection if you missed one. We'll find out in the next section if we did everything correctly for real or not.