May 18, 2022

Xilinx Vivado - Connecting the PS and PL tutorial

I ran across this pair of tutorials several months ago.

This morning I attempted to follow them using my Ebaz board (and making several changes accordingly) and with Vivado 2021.2

Now I want to try it with my Zedboard and Vivado 2019.1 which I just installed (along with the SDK).

So I fire up vivado 2019.1. It doesn't seem to find/remember any of my projects from 2021.2, which is fine actually. I create a new project, calling it zed_pspl_1. It is an RTL project. I skip the opportunity to add sources. I can do that later. I select the Zedboard and Finish.

The tutorial uses the Digilent "Arty-Z7-10", but I don't anticipate any problems with the Zedboard.

I use the "+" button in Sources to add a design source. I call it "logic.c". I set up 2 inputs ports (sw0 and sw1) along with 1 output port (led). I double click on it to get an edit window, get rid of the boilerplate comment and add one line to get:

module logic(
    input a, b,
    output y
    );
    assign y = a & b;
endmodule
I create the constraint file "zedboard.xdc" and copy and paste the Zeboard master file into the edit window for this file. Then I find and uncomment the 3 lines for switches and the LED. I call these sw0, sw1, and led.

Now we are on to "create block design" under "IP integrator". I click on "create block design" on the left. I call the design "mypspl" and a blank design diagram appears. Next I use the "+" button in the Block design diagram and add the Zynq7 processing system. As soon as the block appears, I click on "Run Block Automation". I accept the defaults to interface to DDR and IO and click OK. Connections to DDR and FIXED_IO appear on the diagram.

Now I go to the sources tab, select "logic.v" and right click it. I see "Add Module to block design", click it, and "logic_0" appears on my diagram. It is neatly marked with "RTL" in the center.

Add AXI gpio blocks

We need "AXI gpio blocks to interface between the PS and the PL. We use the "+" at the top of the block design diagram again, search for "axi gpio" and do this twice to add two of these blocks to the diagram.

Now we click on the circular arrow at the top of the diagram to "regenerate" the diagram and clean it up so it looks nicer. Then we click "Run connection automation" and get a dialog. We select the two axi_gpio, but unclick GPIO under each of these since we are going to do our own thing. Click OK and a bunch of new stuff appears along with a lot of routing.

We will use axi_gpio_0 as the input to the PS from our logic block (1 input).
We will use axi_gpio_1 as the output from the PS from our logic block (2 outputs).

Now I double click on the axi_gpio_0 block. This brings up a big dialog. You have to be very careful where you click in the block. Pick a blank area or you will end up with a dialog to configure a specific pin. In the big dialog, go to IP configuration and select "all inputs" and set the GPIO width to be 1 bit wide. Then click OK to dismiss the dialog.

Now hover over the GPIO label on the axi_gpio_0 block until you see a pair of down pointing arrows, then click and a signal appears on the block just below. Now use the mouse (it becomes a pencil), click and drag from that signal to the output of the logic block to make the connection.

Now I put the mouse near the a and b inputs on the logic block, right click to get a menu, select "make external" and I get two external "tabs" marked a_0 and b_0. He uses Ctrl-T as a shortcut for "make external". We want these to match sw0 and sw1 in the constraint file. I move the mouse to each tab, click, and get a dialog "external port properties". I enter "sw0" and hit return to see it change the label on the diagram. I do the same to change b_0 to "sw1".

Now for the axi_gpio_1 block. Double click it, go to IP Configuration. Pick all outputs, gpio width of 1, and OK.

The same game to hover over the GPIO label to get the signal, then make external. Change the external connection name to "led". Note that the diagram now shows "led[0:0]" but that is fine and just indicates a one bit signal.

We are basically done with the diagram, so click Ctrl-S to save it.

Now in the Sources window, find "mypspl", select and right click it, then select "create HDL wrapper", then "let vivado manage and auto update" and OK.

I get 4 critical warnings about parameters relating to PS DDR timing. What can I do other than to ignore them?

Generate bitstream

At the very top of Vivado is an icon with some green and what looks like 4 boxes in a 2x2 arrangement. This is "generate bitstream". I click on this, it tells me that the synthesis and implementation are out of date and need to be rerun. I click OK and wait the usual long time. Note that the upper left of vivado tells you what it is doing and I see a spinning green arrow and the words "Running ...", so I know to just be patient. The long time is longer than usual with all the AXI blocks. My machine is reasonably fast (an Intel i7-3770K with plenty of ram), but it still takes a really long time.

A popup announces the Bitstream has been successfully generated. Use "Cancel" to dismiss the dialog without continuing to other options we don't want. Click File -- Export -- Export Hardware, click on "export bitstream", then OK.

Launch SDK

This takes us to "part 2" (the second video). Still in Vivado. Click File -- Launch SDK and OK. The SDK automatically imports the hardware specification.

I see the file "mypspl_wrapper.bit" in the list on the left.

Click File -- New -- Application Project. I name the project "zed_pspl_code1. Click Next (not Finish) and select the "Hello World" template if it is not already selected. Now click Finish.

Watch the lower right now to see if the SDK is active when you are waiting for slow things to happen.

The left side has a file hierarchy. I expand the second main entry, "zed_pspl_code1", and then expand "src" and then. He renames helloworld.c, so I do also. I rename it to "mypspl.c", then double click it to open it in an editor. He edits the header comment, but I don't.

The right side shows a list of include files and routine names and he uses it as a handy way to browse system libraries. Using Ctrl-Space gives you a menu of options to complete partially typed function names and such.

A bunch of hacking on mypspl.c yields the following. This is the second version where I changed to NAND to a AND.

#include 
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "xparameters.h"


int main()
{
    XGpio input, output;
    int val;

    init_platform();

    XGpio_Initialize(&input, XPAR_AXI_GPIO_0_DEVICE_ID);
    XGpio_Initialize(&output, XPAR_AXI_GPIO_1_DEVICE_ID);

    XGpio_SetDataDirection(&input,1,1);
    XGpio_SetDataDirection(&output,1,0);

    print ( "up and running\n");

    for ( ;; ) {
    	val = XGpio_DiscreteRead(&input,1);
    	// XGpio_DiscreteWrite(&output, 1, ! val);
    	XGpio_DiscreteWrite(&output, 1, val);
    }

    //print("Hello World\n\r");

    cleanup_platform();
    return 0;
}
Typing Ctrl-S saves the changes AND rebuilds the code.

Now the thing to do is to plug in my Zedboard (power and download USB cable) and turn on the power switch.

He starts up a serial terminal. I skip that for now.

At the top of the SDK window is a cute little icon with a tiny red arrow going to 3 green boxes in a path. This is "Program FPGA". I click this, and see that it has my bitstream file properly selected. I click the program button at the bottom. The bright blue "DONE" led on the Zedboard lights up.

This has the FPGA programmed, but no PS code is running yet. I go to "zed_pspl_code1 in the left column. I select it and right click, get a big menu and "Run As" ... "Launch on Hardware".

And I can play with the switches. The LED is lit except when both switches are on. This is indeed a NAND gate.

It works!

I make a small change to the C code, then use "Run As ..." to reload it. After a warning it does so, and I am testing new code in seconds without any need to reload the FPGA.

What about that console?

The code does a print() when it starts up. I peek at the Zedboard and indeed, there is a USB port labeled "uart". I grab a micro USB cable, and plug it in. On my linux log I see:
2022-05-19T13:32:27.980620-07:00 trona kernel: usb 3-2: new full-speed USB device number 3 using xhci_hcd
2022-05-19T13:32:28.176644-07:00 trona kernel: usb 3-2: New USB device found, idVendor=04b4, idProduct=0008, bcdDevice= 0.00
2022-05-19T13:32:28.178549-07:00 trona kernel: usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=4
2022-05-19T13:32:28.178862-07:00 trona kernel: usb 3-2: Product: Cypress-USB2UART-Ver1.0G
2022-05-19T13:32:28.179082-07:00 trona kernel: usb 3-2: Manufacturer: 2012 Cypress Semiconductor
2022-05-19T13:32:28.245371-07:00 trona kernel: cdc_acm 3-2:1.0: ttyACM0: USB ACM device
I set up a script "zedcon" that does picocom -b 115200 /dev/ttyACM0

The zedboard has a button "PS-Reset". Pushing it yields nothing on the serial port (but the "DONE" led goes out when I push it). So now we need to reload the code. (The board has been running overnight since I finished the above project).

I launch Vivado 2019.1 and select the "zed_pspl_1" project. I open the hardware manager, open target (and autoconnect). And I program the device (the FPGA), now the DONE light is on again.

Now I do File -- Launch SDK. And there is my project. As mentioned above, I select "zed_pspl_code1" in the left column, a right mouse click gives a big menu, and I use Run As -- Launch on Hardware to run my code.

I see wrong baud rate stuff in my terminal window. Picocom is running at 115200. I change to 9600, try "run as" again and see rubbish (but less of it) in the terminal window. So this is a trial and error game.

So, I have tried 9600, 19200, 38400, 57600, 115200, 230400, and 460800 without success.

It may be possible to set the baud rate using XUartPs_SetBaudRate(), but everything I read indicates that it should be running at 115200 baud (but apparently it ain't). I tried setting the uart baud rate myself, but no luck. They say the BSP/bootrom should set the baud rate to 115200, but something isn't right and I can't figure it out.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org