In this tutorial I'll show you how to use the Xilinx EDK to use one of the Virtex-II Pro embedded PowerPC cores to blink some LED's and use the push buttons with interrupts.
System requirements:
To complete this tutorial you must have installed the following software on your PC:
Hardware requirements:
In order to download the complete processor system, you must have the following hardware:
<note tip> You may also use another hardware to complete this tutorial as long as the used FPGA has a PPC405 embedded processor core included! </note>
Start the Xilinx Platform Studio (XPS). After startup it will ask if you want to create a new project or open an existing project.
Select the Base System Builder Wizard and press ok.
Project: select a suitable location for the new project (for example Lab1/system.xmp)
Use Repository Path: Point to the location where you have put the XUPV2 EDK Board Definition File (.xbd), Pcores & Drivers.
Press ok.
Select I would like to create a new design
Vendor: Xilinx
Board: XUP2V
Press next.
Processor: PowerPC
Press next.
Processor Clock Frequency: 300 MHz
Press next.
Deselect all peripherals but not the RS232 UART.
UART Baud: 115200
Deselect all peripherals but not the LEDs and the push buttons.
Push Buttons: Select use interrupt
Press next.
Press next.
The PowerPC core can use directly interfaced on-chip memory (OCM) or memory interfaced with a bus like PLB. In this tutorial we do the later case. We use memory interfaced at the PLB.
The PowerPC requires the interrupt table to be stored at a memory address which is aligned at 64KB.
Change the memory size to 64KB.
Press next.
Deselect Memory Test
Press next.
Press next.
The summary shows the memory regions of the selected peripherals.
Press next and press finish in the next wizard step.
The main window of XPS will be populated with your just created project. At the left side of the XPS is the Project tab:
Lets have a look at the Applications tab:
At the IP Catalog tab are all available IPs you may use in your project's. To use them just double-click the entry.
At the right side of the XPS main window you see the available components and their connection with the various buses.
Lets build the Testapp_Peripheral. Click Device Configuration → Update bitstream.
The IPs will be synthesized and the projects active program will be compiled. Afterwards the compiled project will be placed into the bitstream ready for downloading:
Check at the XUP2V Board that the dip switch SW9 is set to JTAG.
Click Device Configuration → Download bitstream to place the bitstream into the FPGA.
You should see the four LEDs going off and on. The TestApp_Peripheral output at minicom should be:
-- Entering main() -- Running GpioOutputExample() for LEDs_4Bit... GpioOutputExample PASSED. Running GpioInputExample() for PushButtons_5Bit... GpioInputExample PASSED. Read data:0x1F Runnning IntcSelfTestExample() for opb_intc_0... IntcSelfTestExample PASSED -- Exiting main() --
Quiet cool, eh?
Lets start an own sample application. The application will print the current count of push button presses over the UART and light the LED's with the associated pressed button.
Select the Applications tab in the XPS mainwindow at the left side. Select Add Software Application Project.
Enter a suitable application name (like ButtonsAndLights). Press next.
Click Device Configuration → Download bitstream to recreate the bitstream with this new project and place the bitstream into the FPGA.
At the minicom you see the push buttons pressed count. If you press a button an associated LED will light on. The center button drives all LEDs.
Lets have a look at the source code:
#include "xparameters.h" #include "stdio.h" #include "xbasic_types.h" #include "xintc.h" #include "xgpio.h" #include "xexception_l.h" #define BTN_RIGHT 0x0001 #define BTN_LEFT 0x0002 #define BTN_DOWN 0x0004 #define BTN_UP 0x0008 #define BTN_CENTER 0x0010 static volatile unsigned int button_count = 0; static XIntc InterruptController; static XGpio Buttons, Lights;
The function button_pressed is an interrupt service routine. If the user push a button the interrupt service routine will be invoked. We count the number of button presses (not debounced). We read the pressed button's into the pressed variable and decode the button states. The single LED's will be put on or off.
void button_pressed(void *callback) { unsigned int *count = (unsigned int *)callback; Xuint32 pressed, light = 0; XGpio_InterruptClear(&Buttons, XGPIO_IR_CH1_MASK); if (count != NULL) (*count)++; pressed = XGpio_DiscreteRead(&Buttons, 1); if (~pressed & BTN_LEFT) light |= 1; if (~pressed & BTN_RIGHT) light |= 2; if (~pressed & BTN_DOWN) light |= 4; if (~pressed & BTN_UP) light |= 8; if (~pressed & BTN_CENTER) light |= 0x0F; XGpio_DiscreteWrite(&Lights, 1, ~light); }
In the main function the ISR for the button's interrupt is registered. Afterwards the global Exception (Interrupt) handling of the PPC will be activated.
int main (void) { print("-- Entering ButtonsAndLights main() v1.9 --\r\n"); XExc_Init(); XExc_RegisterHandler(XEXC_ID_NON_CRITICAL_INT, (XExceptionHandler)XIntc_DeviceInterruptHandler, (void *) XPAR_OPB_INTC_0_DEVICE_ID); XIntc_Initialize(&InterruptController, XPAR_OPB_INTC_0_DEVICE_ID); XIntc_Start(&InterruptController, XIN_REAL_MODE); XIntc_Connect(&InterruptController, XPAR_OPB_INTC_0_PUSHBUTTONS_5BIT_IP2INTC_IRPT_INTR, (XInterruptHandler) button_pressed, (void*) &button_count); XIntc_Enable(&InterruptController, XPAR_OPB_INTC_0_PUSHBUTTONS_5BIT_IP2INTC_IRPT_INTR); XExc_mEnableExceptions(XEXC_NON_CRITICAL); if (XGpio_Initialize(&Buttons, XPAR_PUSHBUTTONS_5BIT_DEVICE_ID) != XST_SUCCESS) { printf("Failed to initalize the buttons.\r\n"); } else { XGpio_SetDataDirection(&Buttons, 1, 0xFFFFFFFF); XGpio_InterruptClear(&Buttons, XGPIO_IR_CH1_MASK); XGpio_InterruptEnable(&Buttons, XGPIO_IR_CH1_MASK); XGpio_InterruptGlobalEnable(&Buttons); } if (XGpio_Initialize(&Lights, XPAR_LEDS_4BIT_DEVICE_ID) != XST_SUCCESS) { printf("Failed to initalize the LEDs.\r\n"); } else { XGpio_SetDataDirection(&Lights, 1, 0x00000000); /* Switch all leds off */ XGpio_DiscreteWrite(&Lights, 1, 0x0F); } XExc_mEnableExceptions(XEXC_NON_CRITICAL); printf("Started up.\r\n"); /* Never exit tho main function */ while(1) { printf("=> Button pressed %u times.\r", button_count); } print("-- Exiting main() --\r\n"); return 0; }
I hope you had fun with this short tutorial!