Table of Contents
So...How Do I Do Something That's Actually Useful on the MicroZed?
When I started working with the MicroZed, I began like any good student should. I read everything I could get my hands on, followed some basic tutorials, and scoured the Xilinx forums. But when it came time to put everything together to actually "do something useful", I realized I was in way over my head.
How was I supposed to get data from an Ethernet port into the algorithm I wrote in Vivado HLS? What the hell were all those DMA settings showing up in the DMA configuration widget? How does one write an HLS algorithm that doesn't send its results back to the MicroZed's ARM processor using DMA? These were the questions that were racking my brain.
It took me a really long time reading through a ton of different sources and getting help from experts (I'd particularly like to thank Jonathan Wolff) to answer these questions. So I figured I'd write a tutorial that covers all the hurdles I had to jump over in the hopes that it'll save other people some time.
A (Relatively) Simple Project to Start
The project I'm going to cover in this tutorial involves sending some data from a computer to the MicroZed over Ethernet, having the MicroZed push that data through a simple algorithm running in the Programmable Logic, and then sending the results back to the computer on that same Ethernet link. It looks something like this.
Sounds easy, right? Shoot...I wish it was. If it wasn't difficult, I would have had more time to watch Key and Peele skits on the internet.
The Tools You'll Need to Follow Along
To follow along with this tutorial, you'll need the following:
- A MicroZed board with a Zynq 7010 SoC on it
- An Ethernet crossover cable (RJ45) OR a regular Ethernet cable with an Ethernet switch
- Vivado High Level Synthesis
- Vivado Design Suite
- Xilinx SDK
- All of the source files in these subdirectories (they are organized by the tool or hardware they correspond to)
- The socket-related files in the GNU C Library (if you are running Linux or MacOS with XCode, these should be on your machine already)
The bad news is that the Xilinx products above will cost you more than a top-notch washer/dryer combo. The good news is that once you've convinced your boss to buy them all, this tutorial will help you understand how these three applications can be used together to create a fully-functional system.
The Breakdown and What You'll Learn
Part of the reason that building an application like this is so difficult is that it involves using three different Xilinx tools, and each one of those tools has a thick ass manual that would take weeks to read through. I'm not saying they are bad tools by any means—I think they're excellent. But it's no walk in the park to go from reading those manuals to mastering the tools. Hence, why I'm writing this tutorial. Here is how things are going to be laid out.
Chapter 1: Writing the GetCentroid Algorithm in HLS
In this first chapter, we'll write our data processing algorithm in Vivado High Level Synthesis and turn it into an IP product that Vivado Design Suite can ingest. Along the way, we'll tackle the following questions:
- How do we use Vivado HLS to design our own IP from C/C++ code?
- What is an HLS Stream and how can we use it to write sleek and efficient code?
- How do we use the HLS directives to pipeline and parallelize our algorithm?
- How do we get data out of our HLS algorithm without using DMA like they show in every other tutorial?
- What's the best way to see how our algorithm will behave and test it out?
Chapter 2: Creating a Vivado Design that Uses Our Algorithm
Next, we'll build a block design in Vivado Design Suite that describes how the data is going to flow from the ARM microprocessor (after being received by a UDP server) to our algorithm. We'll address these questions:
- How do we insert the IP we created in HLS into our Vivado design?
- How do we connect the ARM processor to the Programmable Logic and configure it?
- How do we set up interrupts from the Programmable Logic to the Processor?
- How do we generate a bitstream and export it to SDK so that we can access it from the ARM processor?
Chapter 3: Writing the lwIP UDP Server Portion in Xilinx SDK
Finally, we'll write the code for our lwiP UDP server, DMA mover, and interrupt handler in Xilinx SDK. This code will run on the ARM processor inside the MicroZed. We'll dive pretty deep into the source code for our UDP server and try to answer the following:
- How do we setup the interrupt controller and write interrupt service routines in SDK?
- Where do we look for all the function definitions for various peripherals on the Zynq7010?
- How do the high level function calls relate to the low-level memory map reads and writes?
- How do we do simple DMA transfers and make sure that the data gets to our IP core?
- How do we insert our own custom code into the UDP receive callback function?
- How do we read a result from an HLS algorithm if it's not a slave-to-master DMA transfer?
My real hope is that after you get through this tutorial, you'll have answers to all these questions. And armed with this information, you should be able to write your own custom application to do something useful. So if it sounds like something that'll be useful to you, let's begin!