ZedBoard GPIOs Control Via AXI4 Peripheral

Author: Farid M, https://embeddeddesign.org/

In this tutorial, I am going to show you how to control GPIOs on the Xilinix Zedboard development kit. As a demo, I will explain how to toggle any of the eight LEDs on the board. This tutorial is a bit similar to the previous tutorial  in the sense that it uses AXI4 for communication between the PS and PL. Thus, to fully get the best of this tutorial, I suggest you complete the tutorial previous tutorial: Creating a Custom IP Block in Vivado. Also to complete this little exercise you need a Zedboard and serial terminal such as Tera Term.

Create a new Vivado Project

In this demo, I am using Vivado 16.4. Open Vivado from the start menu and create a new project, name it and save it in your working directory. Then hit next and select RTL Project, next select Zedboard Zynq as your target hardware. Then, the project window will open up after you hit finish. I named this project AXI4_ToggleLEDs.

Create Block Design

Under IP Integrator, select Create Block design, and name it. Click Add IP and search for ZYNQ7 Processing System, once you make the selection the block diagram will show up as in the figure below:

Image1

Figure1. ZYNQ7 Processing System

Create VHDL File Code

Under the Project Manager, select add sources and create a new VHDL file. In my case I created a sub-folder inside my project and named it VHDL and inside this folder I created a VHDL file that I named LED_Control.vhd. Inside this file copy and paste the following code, and save the file.

----------------------------------------------------------------------------------
-- Author: F.Mabrouk

-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity LEDs_Control is
port (
clock : in std_logic;
reset : in std_logic; 
GPIO_Input : in std_logic_vector(7 downto 0); 
LED_Output : out std_logic_vector(7 downto 0)
);
end LEDs_Control;

architecture rtl of LEDs_Control is
signal GPIO_OutputSignal: std_logic_vector(7 downto 0);
begin

process(clock)
begin 
if(rising_edge(clock)) then
if(reset='1')then
GPIO_OutputSignal<="00000000"; 
else
GPIO_OutputSignal<= GPIO_Input; 
end if; 
end if; 
end process; 

LED_Output<=GPIO_OutputSignal; 

end rtl

Now under Tools select Create and Package New IP. Then,hit next and select Create a New AXI4 Peripheral, hit next and name the IP. In my case, I named it AXI4_ToggleLEDs. hit next and keep everything as shown below:

Image2

Figure2. AXI4 configuration

Here we have selected 4 registers of 32 bit data width. Then, hit next and select Edit IP, and click Finish. A new window will open up, where will will edit the newly created IP .

Now we need to add the VHDL file we wrote to the newly created IP. From the project menu select Add Sources, and hit next and then select Add Files. Then add the LED_Control.vhd file you saved. Then go to AXI4_ToggleLEDs_v1_0_S00_AXI_inst file and do the following changes:

Add this piece of code just above (line17): between  lines Users to add ports here and User ports ends

 port (
-- Users to add ports here
clock : in std_logic;
reset : in std_logic; 
LED_Output : out std_logic_vector(7 downto 0); 
-- User ports ends

Add the below code also after begin ( line 122):

 component LEDs_Control is
port (
clock : in std_logic;
reset : in std_logic; 
GPIO_Input : in std_logic_vector(7 downto 0); 
LED_Output : out std_logic_vector(7 downto 0)
);
end component LEDs_Control;

At line 392 add the code below:

 -- Add user logic here
controller : LEDs_Control
port map (
clock =>clock,
reset=>reset,
GPIO_Input=> slv_reg0(7 downto 0),
LED_Output=>LED_Output
);

Now you go to this file: AXI4_ToggleLEDs_v1_0_S00_AXI_imp and add the following changes:

At line 17 add the code below:

 -- Users to add ports here
clock : in std_logic;
reset : in std_logic; 
LED_Output : out std_logic_vector(7 downto 0); 
-- User ports ends

At line 60 just below port add this code:

clock          : in std_logic;
reset          : in std_logic; 
LED_Output     : out std_logic_vector(7 downto 0);

At line 96 just below port map add these lines of code:

clock =>clock,
reset =>reset, 
LED_Output => LED_Output,

When you are done, hit save and you will see that the files hierarchy changed, and it looks as below:

Image3_1

Figure3. Adder IP files Hierarchy

Now, click on Package IP and hit File Groups then click on Merge Changes from File Groups. Then click on Review and Package and click on Re-Package IP, then hit close so that the newly created window for IP configuration is closed.

Now, on the main project window, where the PS diagram is shown, click and Add IP and look for: AXI4_ToggleLEDs. Once you find it, double click on it so that it is added to the project.Right hand click on clock, reset and LED_Output signals and select Make External.

Then click on Run Block Automation and then click on Run Connection Automation.Then click on Regenerate Layout. When your done click on Validate Design to make sure there is no errors. Then save it. Your system block diagrams will look as below:

Image4_2Figure5. System block diagram

Adding User Constraints File

In the Resources menu, right hand click on Constraints and select add files, then add a constrained file. I created a file, named it: ucf.xdc and saved it under VHDL sub-folder. in the file copy and paste the GPIOs mapping below:

set_property IOSTANDARD LVCMOS33 [get_ports clock]
set_property PACKAGE_PIN Y9 [get_ports clock]
create_clock -period 10.000 [get_ports clock]

#SW7
set_property IOSTANDARD LVCMOS33 [get_ports reset]
set_property PACKAGE_PIN M15 [get_ports reset]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[0]}]
set_property PACKAGE_PIN T22 [get_ports {LED_Output[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[1]}]
set_property PACKAGE_PIN T21 [get_ports {LED_Output[1]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[2]}]
set_property PACKAGE_PIN U22 [get_ports {LED_Output[2]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[3]}]
set_property PACKAGE_PIN U21 [get_ports {LED_Output[3]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[4]}]
set_property PACKAGE_PIN V22 [get_ports {LED_Output[4]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[5]}]
set_property PACKAGE_PIN W22 [get_ports {LED_Output[5]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[6]}]
set_property PACKAGE_PIN U19 [get_ports {LED_Output[6]}]

set_property IOSTANDARD LVCMOS33 [get_ports {LED_Output[7]}]
set_property PACKAGE_PIN U14 [get_ports {LED_Output[7]}]

Under Block Designs, right hand click on design_1 and select Create HDL Wrapper. Then again right hand click on design_1 and select Generate Output Products, then select Out of Context per IP, and hit Generate. When this process is done, hit Ok. Then from the Flow Navigator on the main menu on the left select Generate Bit Stream.

SDK Project

Once the bit stream is generated, go File on the left top corner and click on Export, then Export Hardware, and select Include Bitstream, then hit Ok. Then, right hand click on File again and hit Launch SDK. The SDK project will open up automatically and it should look as below:

Image5Figure5. SDK Project Window

Click on File on top left corner and select New and then select Application Project. Name the project: Adder, then click next and select Hello World and hit Finish.

Now if you look under Adder in the Project Explorer to the left you will see a folder named src. If you click on scrc you will a file named: helloworld.c. Right hand click on this file and select rename and name it: ToggleLEDs.c.

Now open the file ToggleLEDs.c and delete its content, and paste the following source code instead, and then build the project.

#include "sleep.h"
#include "xtime_l.h"
#include "xparameters.h"
#include "xstatus.h"
#include "xil_printf.h"
#include "xuartps_hw.h"
#include "xbasic_types.h"
#include "math.h"
#include "platform.h"

Xuint32 *baseaddr_p = (Xuint32 *) XPAR_AXI4_TOGGLELEDS_0_S00_AXI_BASEADDR;

int main()
{

unsigned char Selected_LED=0;
Xuint32 LedRegister=0;

xil_printf("Toggle LEDS IP Demo\n\r");

xil_printf("Enter the number of the LEDs you would like to toggle (0 to 7), and hit enter: \n");
xil_printf("The following LEDs will be toggled: ");
while(1)
{
  if(XUartPs_IsReceiveData(STDIN_BASEADDRESS))
  {
     Selected_LED=XUartPs_RecvByte(STDIN_BASEADDRESS); //receive data from tera term
     if(Selected_LED==10)
     {
      *(baseaddr_p+0)= LedRegister;
       xil_printf(" \n Enter the number of the LED you would like to toggle (0 to 7): \n");
       xil_printf("The following LEDs will be toggled: \n");
       sleep(1);
     }
     else
     {
      Selected_LED=Selected_LED-48; //convert acii value entered to a decimal value.
      LedRegister^= (Xuint32 )(1<<Selected_LED); //toggle corresponding bits
     }
  }
}

return 0;
}

Zedboard Connection to Serial Ports

Connect the Zedboard as in the image blow: Verify that the two serial ports ( top left corner of the picture ) are connected to your PC: one serial port is used for programming the FPGA and other serial port is used for communication with Tera term. Also make sure the the power switch is ON. A green LED will be on when the board is powered up.

Zedboard2Figure6. Zedboard Serial Port Communication Connections

Serial Port Configuration

Open Tera Term and select connection to USB serial port, then set the correct baud rate by going to Setup and then selecting Serial Port. Set the baud rate to 115200 bps. Click again on Setup and select Terminal, then check Local Echo and change New-line receive and Transmit to: LF and then hit Ok. Below are images of the serial port and terminal setup:

tera TermFigure7. Tera Term Configuration

Programming the FPGA

After you have built the project with no errors, click on Xilinx Tools on top menu and select Program FPGA. When it is programmed a blue LED will turns ON. Then, click on Run As ( by right hand clicking on project name) and select Launch on Hardware. Then you will see the following display on Tera Term. This display concludes this tutorial and it proves that sum of any two values is correct, and that the AXI4 data transfer is working as it should.

Tera term2

Figure9:  Tera Term commands for toggling the LEDs

In the video demo, I am toggling one LED at a time, starting from LED 0. I then toggle all LEDs low and then toggle them all high.

Figure9:  Toggling Zedboard RED LEDs Demo

Conclusion

A custom GPIO Controller IP has been created and tested where AXI4 communication interface between PS and PL has been used. In the next tutorial, I will show you how to use AXI GPIO to achieve same functionality:  to control GPIOs/LEDs on the Zedboard development kit. This demo was in fact meant to just demonstrate the power of Xilinix SoC AXI4 data bus and demo how to make use of it. In my opinion, using AXI4 to just control GPIOs is just an overkill.

If you find any of the projects posted here helpful to you while working on similar projects, or you learned something from any of the topics discussed, please do not hesitate to make a donation, whatever amount you can afford, just as a gesture of appreciation and to keep this website alive and progressing so that its benefits extends to many younger engineers and students around the globe.

Author: Farid M, https://embeddeddesign.org/

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.