Introduction

In this tutorial we will access the Programmable Logic (PL)
of a Zynq-7000 from its Processor System (PS) to control the LEDs of the Xilinx
Zynq Board ZC702. This tutorial is realized using Vivado 2016.2 but can easily
be adapted for other releases. Also, even if this tutorial targets a ZC702, the
same process can be used for other Zynq boards as the ZYBO or the ZedBoard.

Create the Hardware Design in Xilinx Vivado

Open Vivado 2016.2 and create a new RTL project. Create a
new BD and add a ZYNQ7 PS IP. Connect the input M_AXI_GP0_ACLK of the ZYNQ7 PS
to its output FCLK_CLK0 (these steps are explained in detail in the tutorial 8
- First use of the Zynq-7000 Processor System on a Zynq Board).

To access the LEDs of the ZC702 board from the PS we will
use a bloc called AXI GPIO IP. Add the AXI GPIO IP using the IP catalog.

Figure 1 - Add the AXI GPIO IP using the IP catalog

An interesting feature in Vivado is “Run Connection
Automation”. Clicking on this will ask the tool to connect the AXI GPIO IP
to the ZYNQ7 PS IP for us. Click on “Run Connection Automation”.

Figure 2 - Vivado IPI - Run Connection Automation

Select “All Automation” in the “Run Connection
Automation” window.

Figure 3 - “Run Connection Automation” window

Vivado has added two blocks, the Processor System Reset and
the AXI Interconnect IPs, needed to connect the ZYNQ7 PS IP to the AXI GPIO IP

Figure 4 - Our system

Double click on the AXI GPIO IP to configure it. In the “board”
part make sure that the board interface for “GPIO” is set to “Custom”.

Figure 5 - AXI GPIO IP customisation - Board

In the part IP configuration, select “All Outputs”
and set the “GPIO Width” to 8 and close the AXI GPIO GUI.

Figure 6 - AXI GPIO GUI

Validate the design. You should
have no error. If we open the “Address Editor” page in the BD, we can
see the memory map of all the IPs in the design. We can see that Vivado as
assigned the address 0x41200000 to our GPIOs.

Figure 7 - Address Editor

Generate the BD output products and create an HDL wrapper.
Run synthesis and open the synthesized design. In the device editor, assign the
gpio_sw output ports to the FPGA pins corresponding to the LEDs.

Ports name

Package Pin

I/O Std

User Led

Gpio_sw_tri_o[7]

E15

LVCMOS25

DS19

Gpio_sw_tri_o[6]

D15

LVCMOS25

DS20

Gpio_sw_tri_o[5]

W17

LVCMOS25

DS21

Gpio_sw_tri_o[4]

W5

LVCMOS25

DS22

Gpio_sw_tri_o[3]

V7

LVCMOS25

DS18

Gpio_sw_tri_o[2]

W10

LVCMOS25

DS17

Gpio_sw_tri_o[1]

P18

LVCMOS25

DS16

Gpio_sw_tri_o[0]

P17

LVCMOS25

DS15

Figure 8 - Assign Package Pins

Press “Ctrl+S” to save the constraints. As we don’t
have any constraints file in our design, Vivado will suggest us to create a new
constraints file to store the Pins constraints. Create a new file called “phys_const”
and click OK.

Figure 9 - Create a new constraints file to store the
created constraints

Generate the Bitstream, export the Hardware to SDK
(including the Bitstream) and launch SDK.

Create the Software Project in Xilinx SDK

Create the application in SDK

Create a new application project (“File > New >
Application Project”) with a new Board Support Package (BSP).

Figure 10 - New application project in Xilinx SDK

In the project templates, select “Hello World”. Launch the
application on the board and see if you can get the “Hello World” in the UART
console (this step is explained in detail in the tutorial 8 - First use of the
Zynq-7000 Processor System on a Zynq Board).

Control the LEDs

To access the LEDs we have added an AXI GPIO IP in our PL
design. The BSP created by SDK should contains the drivers to control this IP.
Expand the BSP in your project (as shown in the Figure 11). Under “libsrc”
you should see “gpio_v4_1” (with another version if you are using
another version of Vivado/SDK).

Figure 11 - Content of the BSP

Open the file “helloworld.c” of your application
project.

First we need to initialize the pointers to the GPIOs. For
this, I have used the function int XGpio_Initialize(XGpio
* InstancePtr, u16 DeviceId) which is declared in the file xgpio.h
(the content of the function can be found in the file xgpio_sinit.c).
This function needs two parameters, InstancePtr, which is the pointer to
the GPIOs to be initialized and DeviceId. For the parameter InstancePtr,
create a new structure called myGPIO of type XGpio and
assign its adress to the function. For the parameter DeviceId, we can put
the constant XPAR_AXI_GPIO_0_DEVICE_ID which is declared in the file xparameters.h.

Then to change the LEDs value, I have used the function voidXGpio_DiscreteWrite(XGpio * InstancePtr, unsigned
Channel, u32 Data) which is also declared in the file xgpio.h
(the structure of the function can be found in the file xgpio.c). The
parameter InstancePtr is the address of the XGpio
structure created previously, set the parameter Channel to 1 and the
parameter Data to the value (between 0x00 and 0xFF) you want to display
on the LEDs.

You can find the content of my file in annexe of this
document.

Run the Software in Debug mode

Launch a Xilinx C/C++ debug application (GDB) and run it
(see tutorial 8 - First use of the Zynq-7000 Processor System on a Zynq Board).
Execute the code step by steps using the “Step Over” icon or
by pressing “F6”.

After the line “success = XGpio_Initialize(&myGPIO,
XPAR_AXI_GPIO_0_DEVICE_ID);” has been executed, look at the value of myGPIO
in the variable window (if not on the screen, click Window > Show View
> Variables). We can see that the value of myGPIO->BaseAddress is
0x41200000 (same value as we have seen previously in the “Address Editor”
of Vivado).

Figure 12 - Variables window in SDK

Continue
the execution of the code by pressing the “Resume” icon or
by pressing “F8”. You should see the value of the LEDs change on the
ZC702 board.