Tutorial Overview
In the previous example, we created a project using the BSB and all of the work related to the hardware design was done by the BSB. In this example, we will create the same simple project, but this time we will add the GPIO for the LEDs manually. This way we will learn the process of adding extra peripherals to our design and we will also better understand the hardware design features of XPS.
This tutorial contains screenshots to guide you through the entire implementation process. Click on the images to view a higher resolution.
What you will learn
As in the previous example, we will create the initial project using the BSB and add software applications. In addition, we will step through:
- How to add a standard IP peripheral without the BSB
- How to add constraints to your design to make links to external hardware (eg. LEDs)
Requirements
Before following this tutorial, you will need to do the following:
- Buy an ML505/ML506/ML507 or XUPV5 board if you don’t already have one. Xilinx supplies the ML50x boards, but the best deal is the XUPV5 from Digilent. Click the Digilent link for more information.
Create the Basic Project
Follow these steps to create the basic project:
- Open XPS. From the dialog box, select “Base System Builder wizard” and OK.
- You will be asked to specify which folder to place the project. Click “Browse” and create a new folder for the project. Click “OK”.
- We are given the choice to create a new project or to create one using the template of another project. Tick “I would like to create a new design” and click “Next”.
- On the “Select Board” page, select “Xilinx” as the board vendor. Then select the board you are using (eg. “Virtex 5 ML505 Evaluation Platform”). Select “1” as the board revision. Click “Next”. (Note: If you are using the XUPV5 (ML509) board, you might find that it is not listed. Select “Virtex 5 ML505 Evaluation Platform” instead.)
- On the “Select Processor” page, we normally have a choice between using the PowerPC “hard” processor, or the Microblaze “soft” processor. Since the Virtex-5 does not contain any PowerPCs, we can only select Microblaze. Click “Next”.
- On the “Configure Microblaze” page, select the clock frequency to be 125MHz. We will use the RS232 port for debugging rather than the JTAG, so select “No debug”. Click “Next”.
- In selecting the Additional IO Interfaces, leave
RS232_Uart_1
andDIP_Switches_8Bit
ticked and un-tick everything else. - On the “Add Internal Peripherals” page, click “Next”.
- On the “Software Setup” page, select
RS232_Uart_1
for both STDIN and STDOUT. The Base System Builder can produce sample software applications to run on the Microblaze and test the memory and peripherals. For this project we will not need them as we will create our own. Un-tick “Memory Test” and “Peripheral Test”. Click “Next”. - Click “Generate”.
- Click “Finish”.
- If you are using the XUPV5 (ML509) board and you selected “Virtex 5 ML505 Evaluation Platform” in step 4 above, you must select the right Virtex-5 version in the project settings. Select “Project->Project Options” and set the Virtex-5 version to “XC5VLX110T”, package “FFG1136” and speed grade “-1”.
Create a Simple Application
Now that the basic project is made, we can create a simple software application to run on the Microblaze to test the DIP switches.
- Select the Applications tab. You will see a software application already there called
Default: microblaze_0_bootloop
. The purpose of this application is to occupy the Microblaze in the case that there is no other software application in the design. It simply keeps the Microblaze running in an endless loop. - Double click “Add Software Application”.
- For the project name type “DIPTest”. For the processor select
microblaze_0
. Click “OK”. - From the Applications tab, right click on the software application
Default: microblaze_0_bootloop
and select “Mark to Initialize BRAMs”. The icon will now have a small red cross signifying that it will not run on the Microblaze. - Right click on the software application we just created “Project: DIPTest” and select “Mark to Initialize BRAMs”. The red cross on the icon of our software application should have been removed signifying that it will run on the Microblaze.
- From the menu select File->New, then select “Text file”. Copy the following code into the new file. Save the file as
DIPTest.c
in a folder called “DIPTest” within the project folder.
#include "xparameters.h"
#include "xbasic_types.h"
#include "xgpio.h"
#include "xstatus.h"
XGpio GpioInput;
int main (void) {
Xuint32 status;
Xuint32 DataRead;
Xuint32 OldData;
// Initialize the GPIO driver so that it's ready to use,
status = XGpio_Initialize(&GpioInput,
XPAR_DIP_SWITCHES_8BIT_DEVICE_ID);
if (status != XST_SUCCESS)
return XST_FAILURE;
// Set the direction for all signals to be inputs
XGpio_SetDataDirection(&GpioInput, 1, 0xFFFFFFFF);
// Initialize the old data register
OldData = 0xFF;
while(1){
// Read the state of the DIP switches
DataRead = XGpio_DiscreteRead(&GpioInput, 1);
// Send the data to the UART if the settings change
if(DataRead != OldData){
xil_printf("DIP Switch settings: 0x%2X\r\n", DataRead);
OldData = DataRead;
}
}
return 0;
}
- In the “Project:DIPTest” tree, right click on “Sources” and select “Add existing files”. Select the
DIPTest.c
file that we just created and click “OK”. - Right click on the “Project: DIPTest” application and select “Generate Linker Script” and click “Generate”.
- Select “Software->Generate Libraries and BSPs” from the menu.
- We can now download our hardware description and software application to the FPGA. Select “Device Configuration->Download bitstream”. When the application is running and Hyperterminal is open, the DIP switch settings should be seen. Change the DIP switches to see the UART message change.
The simple C program that we added to this project simply reads the DIP switch settings and sends a message with that data to the UART.
Add the GPIO for the LEDs
Now we will manually add the second GPIO for the LEDs.
- In the IP Catalog tab, open the “General Purpose IO” tree.
- Right click on “XPS General Purpose IO” and select “Add IP”.
- In the “System Assembly View” using the “Bus Interface” filter, you will see the new GPIO instance called
xps_gpio_0
. Click on the instance and rename it toLEDs_8Bit
. XPS automatically modifies thesystem.mss
andsystem.mhs
files to include the new IP details. - Connect the instance to the PLB bus by opening the
LEDs_8Bit
tree and selectingmb_plb
for the “SPLB” bus connection. - Double click on the
LEDs_8Bit
instance. We can modify the instance parameters using this dialog box. type8
for the “GPIO Data Channel Width” and click OK. - Select the “Ports” filter and open the
LEDs_8Bit
tree. - The
GPIO_IO
net should display “No Connection”. Click on “No Connection” and typefpga_0_LEDs_8Bit_GPIO_IO
to give the net a name. - Click the net again to bring down the drop-down menu and select “Make External”. The newly created net should now be in the “External Ports” tree. XPS automatically modifies the
system.mhs
file to include the new external port. - Select the “Addresses” filter.
- Click the
LEDs_8Bit
size drop-down menu and select 64K. Then click “Generate Addresses”. XPS automatically reconfigures the memory map and gives the LEDs GPIO a base address and a high address. It also automatically modifies thesystem.mhs
file to update the IP address details.
We have now created an instance of the GPIO peripheral in our design.
Modify the Constraints (.UCF) File
The remaining details to include in the hardware description are the external pin connections of the LEDs. This is specified in the system.ucf
file which is up to the user to modify according to the external hardware configuration (ie. How the FPGA pins are wired up on the ML505 board). Follow these steps to modify the constraints file:
- Click the Project tab, open the “Project files” tree and double click the UCF file to open it.
- Find the comment “## IO Devices constraints” and add the following lines of code below it:
#### Module LEDs_8Bit constraints
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<0> LOC = AE24;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<0> IOSTANDARD=LVCMOS18;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<0> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<0> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<0> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<1> LOC = AD24;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<1> IOSTANDARD=LVCMOS18;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<1> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<1> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<1> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<2> LOC = AD25;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<2> IOSTANDARD=LVCMOS18;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<2> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<2> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<2> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<3> LOC = G16;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<3> IOSTANDARD=LVCMOS25;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<3> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<3> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<3> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<4> LOC = AD26;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<4> IOSTANDARD=LVCMOS18;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<4> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<4> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<4> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<5> LOC = G15;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<5> IOSTANDARD=LVCMOS25;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<5> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<5> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<5> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<6> LOC = L18;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<6> IOSTANDARD=LVCMOS25;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<6> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<6> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<6> DRIVE=2;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<7> LOC = H18;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<7> IOSTANDARD=LVCMOS25;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<7> PULLDOWN;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<7> SLEW=SLOW;
Net fpga_0_LEDs_8Bit_GPIO_IO_pin<7> DRIVE=2;
Modify the Software Application
Now the hardware definitions are complete and we must modify the software application to test the hardware.
- Create a new software application called “LEDTest” and create a new folder for it called “LEDTest” in the project directory.
- From the menu select File->New and copy the code below into the new file. Save the file as
LEDTest.c
in the “LEDTest” folder.
#include "xparameters.h"
#include "xbasic_types.h"
#include "xgpio.h"
#include "xstatus.h"
XGpio GpioOutput;
XGpio GpioInput;
int main (void) {
Xuint32 status;
Xuint32 DataRead;
Xuint32 OldData;
// Clear the screen
xil_printf("%c[2J",27);
// Initialize the GPIO driver so that it's ready to use,
status = XGpio_Initialize(&GpioOutput,
XPAR_LEDS_8BIT_DEVICE_ID);
if (status != XST_SUCCESS)
return XST_FAILURE;
// Set the direction for all signals to be outputs
XGpio_SetDataDirection(&GpioOutput, 1, 0x0);
// Initialize the GPIO driver so that it's ready to use,
status = XGpio_Initialize(&GpioInput,
XPAR_DIP_SWITCHES_8BIT_DEVICE_ID);
if (status != XST_SUCCESS)
return XST_FAILURE;
// Set the direction for all signals to be inputs
XGpio_SetDataDirection(&GpioInput, 1, 0xFFFFFFFF);
OldData = 0xFFFFFFFF;
while(1){
// Read the state of the DIP switches
DataRead = XGpio_DiscreteRead(&GpioInput, 1);
// Send the data to the UART if the settings change
if(DataRead != OldData){
xil_printf("DIP Switch settings: 0x%2X\r\n", DataRead);
// Set the GPIO outputs to the DIP switch values
XGpio_DiscreteWrite(&GpioOutput, 1, DataRead);
// Record the DIP switch settings
OldData = DataRead;
}
}
}
- Add the
LEDTest.c
file into the “Project: LEDTest” source files by right-clicking on “Source” and selecting “Add Existing Files”. - Select “Mark to Initialize BRAMs” for the “Project: LEDTest” application and deselect it for the “Project: DIPTest” application.
- Generate the linker script for the “Project: LEDTest” application.
Download and Test the Project
- Open a Hyperterminal window with the required settings. For the correct settings, see Hyperterminal Settings.
- Turn on the ML505 board.
- We can now download our hardware description and software application to the FPGA. From the XPS software, select “Device Configuration->Download Bitstream”.
The simple C program that we added to this project simply reads the DIP switch settings and sends a message with that data to the UART. It also writes the same values to the LEDs. When the application is running and Hyperterminal is open, the DIP switch settings should be seen on the LEDs and on the Hyperterminal screen. Change the DIP switches to see the message change.
After a few changes in the DIP switches, the Hyperterminal output should look similar to the screen shot below:
The project folder for this tutorial can be downloaded in a compressed ZIP file DIP2LED2-EDK10-1.zip . Right-click on the link and select “Save Link As”.
In the next tutorial, Create a Peripheral Using the Peripheral Wizard, we develop our own custom peripheral for reading the DIP switches and writing to the LEDs.