February 6, 200812 minutes
Overview
In this tutorial we will create a simple project that uses our own IP core (instead of using the General Purpose IO core provided by Xilinx) to read from the DIP switches and write to the LEDs. The software application will display the DIP switch values on the LED outputs and also send the DIP switch values to the UART.
Any IP core must connect to the OPB (or PLB) to communicate with the PowerPC. When connected to the OPB, the IP core becomes part of the memory map accessible to the PowerPC. The IP core will have a base address and a high address signifying where in the memory map it resides, and how much of the memory map it occupies. The PowerPC interacts with the IP core as though it were part of the memory.
In this example, we will use the Peripheral Wizard to create a basic IP core that connects to the OPB and implements one 32 bit register. Writing to the IP core through the OPB will allow us to change the contents of the register. The outputs of the register will drive the LEDs. We will modify the core so that reading from it through the OPB will return the DIP switch settings. The diagram below illustrates the peripheral and connections.
Figure: Peripheral for controlling the LEDs and reading the DIP switches
Note that another possibility for this design is to use another register for passing the DIP switch values through to the OPB handler. In this design, only one register was used to keep the design simple and to minimize the changes to the template.
This tutorial contains screenshots to guide you through the entire implementation process. You can click on the images to view a higher resolution when necessary.
Are you using EDK 10.1?
Try the updated version of this tutorial based on the Virtex-5 FPGA on the ML505 board: Create a Peripheral using the Peripheral Wizard
Create the Basic Project using BSB
Follow these steps to create the basic project:
RS232_Uart_1 ticked and un-tick everything else.
plb_bram_if_cntlr_1 and click “Next”.
RS232_Uart_1 for both STDIN and STDOUT. Un-tick “Memory Test” and “Peripheral Test”. Click “Next”.
Create the Peripheral
We now create our custom peripheral using the Peripheral Wizard.
my_peripheral for the peripheral name. Click “Next”.
Modify the Peripheral
The template created by the Peripheral Wizard implements a 32-bit register that we can read and write to via the OPB. When the peripheral is instantiated, we could access the register by reading and writing to the base address of the peripheral. We need to modify this functionality slightly, because of two things:
Follow these steps to modify the peripheral:
pcores\my_peripheral_v1_00_a\hdl\vhdl from the project folder. This folder contains two source files that describe our peripheral: my_peripheral.vhd and user_logic.vhd. The first file is the main part of the peripheral and it implements the interface to the OPB. The second file is where we place our custom logic to make the peripheral do what we need it to do. This part is instantiated by the first file.my_peripheral.vhd. We will need to add two ports to this source code, one for the LEDs and one for the DIP switches.--ADD USER PORTS BELOW THIS LINE and add these two lines of code: LED_Data : out std_logic_vector(0 to 3);
DIP_Data : in std_logic_vector(0 to 3);--MAP USER PORTS BELOW THIS LINE and add these two lines of code: LED_Data => LED_Data,
DIP_Data => DIP_Data,user_logic.vhd. We will need to modify this source code to include the two new ports and to modify the behaviour.--ADD USER PORTS BELOW THIS LINE and add the following two lines of code. LED_Data : out std_logic_vector(0 to 3);
DIP_Data : in std_logic_vector(0 to 3);--USER logic implementation added here and add the following line of code below. This connects the LED port to the first 4 bits of the register output.LED_Data <= slv_reg0(28 to 31);
IP2Bus_Data <= slv_ip2bus_data; and replace it with the code below. Now, when the peripheral is read on the OPB, it will always return the DIP switch settings. As the bus is 32 bits long, we just fill the unused bits with zeros using the “others” keyword. IP2Bus_Data(0 to 27) <= (others=>'0');
IP2Bus_Data(28 to 31) <= DIP_Data(0 to 3);Import the Peripheral
Now we will use the Peripheral Wizard again, but this time using the import function.
my_peripheral. Tick “Use version” and select the same version number that we originally created. Click “Next”. It will ask if we are willing to overwrite the existing peripheral and we should answer “Yes”.
pcores\my_peripheral_v1_00_a\data and select the my_peripheral_v2_1_0.pao file. Click “Next”.
Now we have a peripheral that is ready to use and it should be accessible through the “IP Catalog->Project Repository” in the XPS interface. Note that although we can access it through the IP Catalog, other projects will not find it there because it is only associated with our project, as we specified in the Peripheral Wizard.
Create an Instance of the Peripheral
Now we are ready to create an instance of the peripheral into our project which can then be downloaded into the FPGA and tested by using simple code running on the PowerPC.
my_peripheral IP core in the “Project Repository” group. Right click on the core and select “Add IP”.
my_peripheral_0 to the OPB bus.
my_peripheral_0 tree. There will be two ports listed LED_Data and DIP_Data. Type in a net name for each of them. The net name can be anything you like, but for this project let us call them LED_Data and DIP_Data for simplicity. For each net, use the option “Make External”. If you then click open the “External Ports” tree, you should see these nets listed.
my_peripheral_0 to 64K. Then click “Generate Addresses”. You might ask why 64K when we only have one 32 bit register to address. If you enter 32 bits as a size and then click “Generate Addresses”, XPS automatically changes the size to 64K and calculates the addresses accordingly.

We have now created an instance of the peripheral in our design.
Link the External Ports to FPGA Pins
Now we have made the LED and DIP ports external however we need to link them to specific pins on the FPGA. We will use the schematic for the XUPV2P to get the correct pin numbers for each of the LEDs and DIP switches. Then we modify the User Constraints File (UCF) to include these pin assignments.
#### Module DIPSWs_4Bit constraints
Net DIP_Data_pin<0> LOC=AC11;
Net DIP_Data_pin<0> IOSTANDARD = LVCMOS25;
Net DIP_Data_pin<1> LOC=AD11;
Net DIP_Data_pin<1> IOSTANDARD = LVCMOS25;
Net DIP_Data_pin<2> LOC=AF8;
Net DIP_Data_pin<2> IOSTANDARD = LVCMOS25;
Net DIP_Data_pin<3> LOC=AF9;
Net DIP_Data_pin<3> IOSTANDARD = LVCMOS25;
#### Module LEDs_4Bit constraints
Net LED_Data_pin<0> LOC=AC4;
Net LED_Data_pin<0> IOSTANDARD = LVTTL;
Net LED_Data_pin<0> SLEW = SLOW;
Net LED_Data_pin<0> DRIVE = 12;
Net LED_Data_pin<1> LOC=AC3;
Net LED_Data_pin<1> IOSTANDARD = LVTTL;
Net LED_Data_pin<1> SLEW = SLOW;
Net LED_Data_pin<1> DRIVE = 12;
Net LED_Data_pin<2> LOC=AA6;
Net LED_Data_pin<2> IOSTANDARD = LVTTL;
Net LED_Data_pin<2> SLEW = SLOW;
Net LED_Data_pin<2> DRIVE = 12;
Net LED_Data_pin<3> LOC=AA5;
Net LED_Data_pin<3> IOSTANDARD = LVTTL;
Net LED_Data_pin<3> SLEW = SLOW;
Net LED_Data_pin<3> DRIVE = 12;Create a Software Application
Now we need to create a simple software application to test the peripheral. The program simply needs to read and write to the peripheral through the OPB.
ppc405_0 processor. Click “OK”.Default: ppc405_0_bootloop and select “Mark to Initialize BRAMs” so that this application does not get executed on the PowerPC. It should now have a red cross through its icon.TestApp.c in a new folder called “TestApp” within the project folder.#include "xparameters.h"
unsigned int *my_peripheral =
(unsigned int *) XPAR_MY_PERIPHERAL_0_BASEADDR;
int main (void) {
unsigned int DataRead;
unsigned int OldData;
// Clear the screen
xil_printf("%c[2J",27);
OldData = (unsigned int) 0xffffffff;
while(1){
// Read the state of the DIP switches
DataRead = *my_peripheral;
// Send the data to the UART if the settings change
if(DataRead != OldData){
xil_printf("DIP Switch settings: 0x%X\r\n", DataRead);
// Set the LED outputs to the DIP switch values
*my_peripheral = DataRead;
// Record the DIP switch settings
OldData = DataRead;
}
}
}
The software application simply creates a pointer to the peripheral and makes reads and writes to the peripheral through the pointer. We can obtain the address of the peripheral by looking in the “System Assembly View” using the “Addresses” filter, but in this example, we use the XPAR_MY_PERIPHERAL_0_BASEADDR definition given in the “xparameters.h” file which is created automatically by XPS. By using this definition, instead of a fixed value, we don’t have to modify our code each time we modify the hardware and addresses.
Download and Test the Project
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. 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 MyPeripheral.zip . Right-click on the link and select “Save Link As”.
In the next tutorial, Create a Simple Timer Peripheral, we develop our own timer peripheral so that we can make the LEDs flash.