Table of Contents
3.1: Building a Program in SDK from the lwIP Echo Server Example
One really nice thing about the Xilinx tools is that they come with a lot of example code that you can build off of. We're going to base our ARM program off of the Light-Weight IP (lwIP) Echo Server example that is included with SDK.
3.1.1: Starting a New Project
Assuming you have been following along from the previous chapter, you should have the Xilinx SDK sitting on your screen. Go to File → New → Application Project , which will bring up the new project window. Name your project whatever you like. I chose GetCentroid for simplicity. Keep all the other settings as they are. We'll stick with C files for this portion.
When you enter the project name, SDK will autofill the BSP (Board Support Package) field using the project name you chose as a prefix. On the next screen, you can choose from a number of existing templates. We're going to choose the lwIP Echo Server template. After selecting it, click Finish. It may take awhile for SDK to build the workspace.
When it comes to waiting for SDK, I have a recommendation: never, ever close SDK while it's building something. I did that once and my hard drive got fried. Not sure if I can place the blame completely on SDK, but it's kind of like when you get food poisoning, and then for the rest of your life, the thought of the food you ate right before makes you want to puke.
As the little description window says, the lwIP Echo Server example will immediately transform your MicroZed into a server...right out of the box! It's actually pretty cool to run it as is and take a look at the source files to get an idea of how everything works. We're going to replace some of those files to transform the simple echo server into something we can use to pipe data into our algorithm from the Ethernet port.
3.1.2: Inserting Our Custom Source Files
The application we're going to be creating here is a bit more complicated than the simple lwIP Echo server. But luckily, to get it working, we only have to replace two of the source files in the project (and add one of our own).
The three files you'll need to grab are:
- main.c -
This is our main program file that will initialize and configure all of our hardware. We'll go through each component in a bit of detail in the next few sections. This file also contains the infinite while loop that keeps our UDP server going.
- echo.c -
This file contains all of the code for our lwIP receive callback function. It handles all of the incoming packets and transfers them to our algorithm through either DMA or block memory writes (more on this later). Note: in newer versions of Vivado, you may have to change the ip_addr type to ip4_addr type.
- includes.h - Another include file that allows us to share #DEFINE statements between echo.c and main.c. Note that this file is different than the one we used for our HLS code.
Now we're going to insert these files into our SDK source directory. When we built the project, SDK created a directory called C:/VivadoExamples/GetCentroidDesign/GetCentroidDesign.sdk/GetCentroid/src/ that contains all of the high level source code for the lwIP server (Note that this assumes you named your Vivado project GetCentroidDesign and your SDK project GetCentroid. If you named them something else, your directory structure will differ. Place the three files above in that src directory. You'll have to write over the existing main.c and echo.c files.
After you've done that, open up the three files in the Project Explorer on the left hand side of the SDK GUI. They should be under GetCentroid→src. You may get a complaint about how the files are out of sync, so follow the instructions to refresh them by right-clicking or pressing F5. SDK will automatically compile everything again for you after you refresh them.
Go ahead and click on that little blue and black terminal-looking icon on the top menu bar of SDK to bring up the XSCT Console. This will be one of the most useful tools you have while you're debugging your code. After you've completed these steps, your window should look something like this:
At this point, you're basically ready to run your application. If you're just trying to get things up and running, you can skip ahead to Chapter 3, Section 3. The next subsections are going to delve into the details of how everything works.
3.1.3: Exploring Some of the BSP Code
When we exported the design from Vivado Design Suite and created our project in SDK, a Board Support Package (BSP) was automatically created for us. The BSP does a lot of things, including initializing the processor and setting up the memory. But another thing it does is provide us with some simple C code that we can use to control the algorithm we wrote in HLS.
3.1.3.1: The XGetcentroid Source Files
Let's check out the header file xgetcentroid.h, which we can find in the project explorer under GetCentroid_bsp → ps7_cortexa9_0 → libsrc → GetCentroid_v1_0 → src . This file gives us a list of all the functions we can use to control our IP block. For instance, the function XGetcentroid_InterruptEnable enables interrupts and the function XGetcentroid_Start starts the module. Notice that almost every function requires a pointer to the XGetcentroid structure as an argument. Here's how XGetcentroid is defined.
   typedef struct {
   u32 Ctrl_bus_BaseAddress;
   u32 IsReady;
   } XGetcentroid;
As you can see, it's pretty simple. Just a pointer to its base address and an "IsReady" variable. We'll have to create an instance of that structure and pass it around to all the functions to get things working.
Next, let's check out the source file to see what each one of these functions does. Open up GetCentroid_bsp → ps7_cortexa9_0 → libsrc → GetCentroid_v1_0 → src → xgetcentroid.c in the Project Explorer. You can take a look at the source for any one of those functions and see that really all they are doing is reading and writing memory mapped registers that are defined in GetCentroid_bsp → ps7_cortexa9_0 → libsrc → GetCentroid_v1_0 → src → xgetcentroid_hw.h.
Pretty cool stuff, right? The BSP provides a layer of abstraction that saves us from remembering which registers are which, and having to do bitshifts and all that nastiness. You can think of these as drivers for our program (it's not really an operating system in the conventional sense). We'll be using the functions defined in these files extensively to communicate with our algorithm. If you want to extend the functionality of one of Xilinx's examples, or the one I'm showing you here, these are definitely some of the files you want to investigate.
3.1.3.2: Other Important Source Files
There are several header files and directories we are going to have to be familiar with in order to get our application working, all of which are in GetCentroid_bsp → ps7_cortexa9_0 → include:
- The lwIP directory: This directory contains the function definitions for receiving and sending data over Ethernet, either with UDP or TCP.
- xaxidma.h: This header file contains the function definitions for all of the DMA related operations. We'll be using a few of these.
- xscugic.h: This file defines all of the functions related to the generic interrupt controller.
- xparameters.h: This file has a bunch of #define statements that reveal the addresses of various components, interrupt and device IDs, and other pertinent things.
If you're trying to do something like generate an interrupt from a new block you've added to your design or toggle a GPIO, the files above are where you want to start digging for the specifics of how you do it. After going through this example, hopefully it will be clear how it all works.
In the next section, we'll go through the changes we made to main.c and echo.c to tailor the echo server to do what we want.
← Previous   ...    Next →