Lab 5 – SDK Lab
PowerPC Processor
SDK Lab:
PowerPC Processor
Introduction
This lab guides you through the process of adding timers to an embedded system and writing a software application that utilizes these timers. The Software Developers Kit (SDK) will be used to create and debug the software application.
Objectives
After completing this lab, you will be able to:
• Utilize the OPB timer with interrupt controller
• Assign an interrupt handler to the OBP timer
• Develop an interrupt handler function
• Use SDK Debugger to set break points and view the content of variables and memory
Procedure
This lab extends the hardware design carried out in Lab 1, Lab 2, and Lab 3. In this lab, you will add an OPB timer and an OPB interrupt controller. You will develop software to use the timer module, which generated periodic events that you had added in Lab 2. You will then add the interrupt mechanism to count the number of times the timer-compare events take place

Figure 5-1. Completed Design
This lab comprises several steps, including the writing of an interrupt handler used by the software application to access the OPB timer. Below each general instruction for a given procedure, you will find accompanying step-by-step directions and illustrated figures providing more detail for performing the general instruction. If you feel confident about a specific instruction, feel free to skip the step-by-step directions and move on to the next general instruction in the procedure.
Open the Project Step 1
General Flow for this Lab:

Create a lab5 folder and copy the contents of the lab4 folder into the lab5 folder if you wish to continue with the design you created in the previous lab. Launch Xilinx Platform Studio (XPS) and open the project file located in C:\xup\embedded\ppc\labs\lab5 (if you want to continue with your created design)
If you wish to continue using the design that you created in Lab 4, create a lab5 folder in the C:\xup\embedded\ppc\labs directory and copy the contents from lab4 to lab5
Open XPS by selecting Start Programs Xilinx Platform Studio 8.2i Xilinx Platform Studio
Select Open Recent Project, Click OK and browse to C:\xup\embedded\ppc\labs\lab4
Select system.xmp to open the project
Add Timer and Interrupt Controller Step 2
General Flow for this Lab:

Add the OPB timer and OPB_INTC peripheral to the design from the IP Catalog, and connect them to the system according to the following table.

Add the opb_timer peripheral from the Timers section of the IP Catalog and change its instance name to delay
Add the opb_intc peripheral from the Interrupt section of the IP Catalog.
Connect the timer and interrupt controller as a ‘s’ (slave) device to the OPB bus

Figure 5-2. Add and connect the Interrupt Controller and Timer peripherals
Under the Addresses section, lock down all addresses except for opb_intc and delay.
Select size as 512 bytes from drop down box and click Generate Addresses.

Figure 5-3. Generate Addresses for Interrupt Controller and Timer peripherals
Under the Ports section, enter timer1 as the Interrupt port connection of the delay instance.
Change the net name for the EICC405EXTINPUTIRQ (external interrupt request) port on the ppc405_0 instance to interrupt
Change the net names of the Intr, and Irq ports of the opb_intc_0 instance to timer1 and interrupt, respectively and net names of CaptureTrig0 ports of delay instance to net_gnd respectively.
Double-click on delay to open its parameters box and put a check mark next to “Only One Timer is Present”.
Click OK to accept the changes and close the dialog box
Configure the BSP Step 3
General Flow for this Lab:

Enter timer_int_handler in the interrupt handler function field for the delay instance under Software Platform Settings. Generate the Libraries and update the xparameters.h file
Select Software Software Platform Settings and enter timer_int_handler as the interrupt handler function for the delay instance.
You will create this function in the next section.

Figure 5-4. Specify Interrupt Handler for Timer Peripheral
Click OK to accept the settings
Select Software Generate Libraries and BSPs to update the generated libraries and xparameters.h file
Launch Platform Studio Software Development Kit (SDK) Step 4
General Flow for this Lab:

![]()
Launch SDK and set up the project environment in order to begin software development.
Open SDK by selecting Software Launch Platform Studio SDK
If this is the first time that Platform Studio SDK has opened, a Welcome tab appears on the right side with five icons.
• Import XPS Design – How to import an XPS Design and create a software application for it
•Overview – Find out what Eclipse is all about
•Tutorials – Let us guide you through Eclipse end-to-end tutorials
•Samples – Explore Eclipse development through code samples
•What’s New – Find out what’s new in this release
You can click on any of the topics and navigate through the introduction. You can close the Welcome window when you are ready to proceed.
Creating a C Project Step 5
General Flow for this Lab:

![]()
Create a new C application project for a selected Platform Studio design.
Select Create a new SDK Application Project and click Next.

Figure 5-5. Managed Make C Project
A screen appears for entering the project name; enter the name of the project: sdk_lab. This SDK project will be stored in the \lab5\SDK_projects\sdk_lab.

Figure 5-6. New Project
Click Finish
Managing Build Configuration Step 6
General Flow for this Lab:

![]()
Configure the build options for the project.
Click on the C/C++ Projects tab on the left side

Right-click on sdk_lab and select Properties to open the Properties dialog box (or select Project Properties from the menu)
In the left hand window of the Properties for sdk_lab, select the C/C++ Build item
Select and view different configuration settings for the application build. These configuration settings are used in the generation of the makefile
Click Cancel to exit the Properties for sdk_lab dialog box. We will make changes in this dialog to add the linker script later in the lab
Adding Source Files Step 7
General Flow for this Lab:

![]()
Import the system_timer.c source files for the SDK project
Select File Import to bring up the Import wizard. Double-click on File System and browse to the c:\xup\embedded\xupv2pro\sources directory. Check the system_timer.c source file and click Finish to add the file to the project
In the left hand Navigator tab, double click on the system_timer.c file to open it in the editor. The file is built as soon as it is opened, and note that both the Problems and Console tabs on the bottom report several compilation errors. The project is automatically built each time files in the project are edited and saved. Note also that the project outline on the right side is updated to reflect the libraries and routines used in the source file
In the Problems tab, double-click on the second red x for the parse error. This will bring you to the line 33. Add the missing semicolon to the printf statement and save the file. The error messages should disappear.
In the Outline tab on the right, double-click on the timer_int_handler function. This will take you to the function in the source file. Note that it has only been stubbed out; you will complete the function in the next step
Writing the Interrupt Handler and Compiling the Code Step 8
General Flow for this Lab:

Create a new global variable to be used in the interrupt handler code where the other global variables are declared:
unsigned int j=0;
Save the file, and note that the source file gets built whenever you save. Note that the error on the undeclared variable now goes away.

![]()
Create the interrupt handler for the OPB timer
Go to where the interrupt handler function has already been stubbed out in the source file (a fast way to do this is to double-click on the function in the outline view). Notice that the interrupt handler function is called timer_int_handler. This name must match the name specified in the OPB timer peripheral options, as shown in Figure 5-4. If the name does not match exactly, the interrupt handler will not be connected to the interrupt and you will get error while compiling
Create new local variables for the timer_int_handler function:
unsigned int csr;
The first step in creating an OPB timer interrupt handler is to verify that the OPB timer caused the interrupt. This information can be found in the OPB Timer Control Status Register. Open the API documentation to determine how the Control Status Register works.
In the XPS System Assembly View window, right-click the opb_timer instance named delay and select View PDF Datasheet to read the data sheet
Go to the Register Description section in the data sheet and study the TCSR0 Register. Notice that bit 23 has the following description:
Timer0 Interrupt
Indicates that the condition for an interrupt on this timer has occurred. If the timer mode is capture and the timer is enabled, this bit indicates a capture has occurred. If the mode is generate, this bit indicates the counter has rolled over. Must be cleared by writing a 1
Read:
0 - No interrupt has occurred
1 - Interrupt has occurred
Write:
0 No change in state of T0INT
1 Clear T0INT (clear to ’0’)
The level 0 driver for the OPB timer provides two functions that read and write to the Control Status Register. View the timer API doc by right-clicking on the delay instance in the System Assembly View and selecting Driver:tmrctr_v1_00_b View API Documentation. In the API document, click on the File List link at the top of the document, then click on the link labeled xtmrctr_l.h in the file list. This brings up the document on identifiers and the low-level driver functions declared in this header file. Scroll down in the document and click on the link for the XTmrCtr_mGetControlStatusReg( ) function to read more about this function. Use this function to determine whether an interrupt has occurred. The following is the pertinent information found in the OPB timer documentation:
XTmrCtr_mGetControlStatusReg ( BaseAddress, TmrCtrNumber )
Get the Control Status Register of a timer counter
• Parameters:
• BaseAddress is the base address of the device.
• TmrCtrNumber is the specific timer counter within the device, a zero-based number, 0 -> (XTC_DEVICE_TIMER_COUNT - 1)
•Returns:
• The value read from the register, a 32-bit value
Add the XTmrCtr_mGetControlStatusReg function call to the code with the associated parameters. The resulting 32-bit return value should be stored in the variable csr. While typing in the name of the function, stop at XTmrCtr and hit CNTL-SPACE. This will bring up function-completion a dialog with a list of functions that begin with XTmrCtr. As you continue to type the list will narrow. This is useful for quickly finding types and functions
csr = XTmrCtr_mGetControlStatusReg(baseaddr, 0);
Note: Substitute baseaddr with the base address for the delay peripheral. Refer to
xparameters.h
Using the value returned to csr, test to see if bit 23 is set by ANDing csr with the XTC_CSR_INT_OCCURED_MASK parameter. If the interrupt was taken, increment a counter. The count value should then be displayed by using the my_led peripheral. Use the MY_LED_mWriteReg() function that you used in the previous lab. The value should also be printed by using printf
Clear the interrupt by using the following function call:
XTmrCtr_mSetControlStatusReg(baseaddr, 0, csr);

Save the file, which will compile the source. Look in the Console window for the following information:
1. What is the size of the compiled program?
text segment:
data segment:
bss segment:
Total in decimal:
Total in hexadecimal:
2. Why do you think the program is so big?
__________________________________________________________
__________________________________________________________
Change all printf calls to xil_printf
xil_printf provides the same functionality as printf with the exception of the floating-point handling.
Save /recompile the program
3. What is the size of the compiled program?
text segment:
data segment:
bss segment:
Total in decimal:
Total in hexadecimal:
![]()
Assign xupv2pro_LinkScr.ld as the linker script for building the project and compile the application.
In the C/C++ Projects tab on the left side, right-click on sdk_lab and select Properties to open the Properties dialog box (or select Project Properties from the menu)
In the left hand window, select the C/C++ Build item. In the Configuration Settings window select Linker Script under PowerPC C Linker tree in the Tool Settings tab and click Add button
(Figure 5-8)

Figure 5-8. Adding Linker Script
Click on Browse button and select the xupv2pro_LinkScr.ld file from c:\xup\ embedded\sources\ and click OPEN and then click OK
Click OK again
The program will be recompiled using the just added linker script. Note that the size of some of the segments is different as the new linker script has different number of segments compared to the default linker script
Accessing the ELF file in XPS Step 9
General Flow for this Lab:

After you build your SDK project, you will commonly want to access the resulting executable ELF file in XPS to merge it into the FPGA download bitstream. You will add a new Software Application to the XPS project that points to the SDK built ELF file, and make the previously existing software application inactive. Update the BRAMs in bitstream with the new code via the ISE software.
In the XPS, click on Applications tab
Select Software Add Software Application Project, and specify the name “SDK_Proj”.
Select the Project is an ELF-only Project option. The path should default to the executable generated from SDK. The only purpose for this software project is to point to the ELF file produced by SDK.

Figure 5-9. Create a new Application project in XPS
Click <OK>. The new software project now appears in the XPS Applications tab.
In the XPS Applications tab, right-click on the SDK_Proj project and set Mark to Initialize BRAMs
In the XPS Applications tab, right-click on the TestApp_Memory software project and select Make Project Inactive from the context menu

Figure 5-10. New Application
Testing in Hardware Step 10
General Flow for this Lab:

![]()
Generate the bitstream in XPS and download to the XUP board.
Connect and power the XUP board
Click the Download Bitstream to FPGA button
This will configure the FPGA and you should observe a message on the hyperterminal window indicating the count value. The LEDs should be flickering.

Figure 5-11. Hyperterminal Output
Debugging Using SDK Step 11
General Flow for this Lab:

![]()
Configure Target Connection Settings
On the SDK Menu, select Run Run…
This will present a screen summarizing the existing Launch Configurations
Under Configurations, select Xilinx C/C++ ELF
Click on New to add a new Launch configuration and set the Project name to sdk_debug

Figure 5-9. Setting Up Run Configuration
Click Apply and then on the Run button to download the application and run it using XMD
You should see output displayed on hyperterminal since the program is running.
Open the Console view and click on the Terminate button (red button) to stop the running process

Figure 5-10. Terminating a Running XMD Application
Click OK to close the warning
![]()
Launch Debugger and debug.
On the SDK Menu, select Run Debug…
This will present a screen summarizing the existing Launch Configurations.
Click on Debug. If a dialog box appears asking you to confirm whether to switch to the Debug Perspective, click Yes
This opens the Debug perspective. The debugger is automatically connected to the processor via XMD. The processor will be suspended automatically (breakpoint) at the first statement in main().
Click on the Resume button. The application will run

Figure 5-11. Resuming an Application
Click on Thread[0] (Running) line in the Debug window (left) and the Suspend and Terminate buttons will become available

Figure 5-12. Suspending a Running Application
Click on the Suspend button
Right click in the Variables tab and select Add Global Variables … All global variables will be displayed. Select jand click OK
Right click on j and select Enable

Figure 5-13. Enabling Variables
![]()
Monitor variables and memory content.
On line 21 in system_timer.c source window, double-click to set the breakpoint

Figure 5-14. Setting breakpoint
Click on Resume button to continue executing the program up until the breakpoint.
As you do step over, you will notice that the j variable value is changing.
Click on the memory tab, enter the base address of the my_led peripheral, and click evaluate
to view the memory content starting at the my_led base address.
The base address can be found in the xparameters.h file or in the system view of XPS.
Click the Resume button to continue execution of the program.
Notice that the value written to the base address of the my_led peripheral is incrementing

Figure 5-15. Viewing Memory Content of the my_led peripheral (0x7d800000)
Terminate the session by right-clicking on sdk_lab in the debug pane and selecting Terminate

Figure 5-16. Terminating a Debug Session
Close the SDK application
Conclusion
This lab led you through adding an OPB timer and interrupt controller, and assigning an interrupt handler function to the interrupting device via the software platform settings. You developed an interrupt handler function and tested it in hardware. Additionally, you used the SDK debugger to view the content of variables and memory.
1. What is the size of the compiled program?
text segment: 45449
data segment: 1972
bss segment: 8556
Total in decimal: 55977
Total in hexadecimal: daa9
2. Why do you think the program is so big?
The printf function uses significant amount of code space.
3. What is the size of the compiled program?
text segment: 12758
data segment: 848
bss segment: 8504
Total in decimal: 22110
Total in hexadecimal: 565e
Completed MHS File
# ##############################################################################
# Created by Base System Builder Wizard for Xilinx EDK 8.2 Build EDK_Im.14
# Tue Aug 29 14:15:28 2006
# Target Board: Xilinx XUP Virtex-II Pro Development System Rev C
# Family: virtex2p
# Device: xc2vp30
# Package: ff896
# Speed Grade: -7
# Processor: PPC 405
# Processor clock frequency: 300.000000 MHz
# Bus clock frequency: 100.000000 MHz
# Debug interface: FPGA JTAG
# On Chip Memory : 64 KB
# ##############################################################################
PARAMETER VERSION = 2.1.0
PORT fpga_0_RS232_Uart_1_RX_pin = fpga_0_RS232_Uart_1_RX, DIR = I
PORT fpga_0_RS232_Uart_1_TX_pin = fpga_0_RS232_Uart_1_TX, DIR = O
PORT sys_clk_pin = dcm_clk_s, DIR = I, SIGIS = CLK, CLK_FREQ = 100000000
PORT sys_rst_pin = sys_rst_s, DIR = I, RST_POLARITY = 0, SIGIS = RST
PORT dip = DIP, DIR = I, VEC = [0:3]
PORT push = PUSH, DIR = I, VEC = [0:4]
PORT led = fpga_0_LEDs_4Bit_GPIO_d_out, DIR = O, VEC = [0:3]
BEGIN ppc405
PARAMETER INSTANCE = ppc405_0
PARAMETER HW_VER = 2.00.c
BUS_INTERFACE JTAGPPC = jtagppc_0_0
BUS_INTERFACE IPLB = plb
BUS_INTERFACE DPLB = plb
PORT PLBCLK = sys_clk_s
PORT C405RSTCHIPRESETREQ = C405RSTCHIPRESETREQ
PORT C405RSTCORERESETREQ = C405RSTCORERESETREQ
PORT C405RSTSYSRESETREQ = C405RSTSYSRESETREQ
PORT RSTC405RESETCHIP = RSTC405RESETCHIP
PORT RSTC405RESETCORE = RSTC405RESETCORE
PORT RSTC405RESETSYS = RSTC405RESETSYS
PORT CPMC405CLOCK = proc_clk_s
PORT EICC405EXTINPUTIRQ = interrupt
END
BEGIN ppc405
PARAMETER INSTANCE = ppc405_1
PARAMETER HW_VER = 2.00.c
BUS_INTERFACE JTAGPPC = jtagppc_0_1
END
BEGIN jtagppc_cntlr
PARAMETER INSTANCE = jtagppc_0
PARAMETER HW_VER = 2.00.a
BUS_INTERFACE JTAGPPC0 = jtagppc_0_0
BUS_INTERFACE JTAGPPC1 = jtagppc_0_1
END
BEGIN proc_sys_reset
PARAMETER INSTANCE = reset_block
PARAMETER HW_VER = 1.00.a
PARAMETER C_EXT_RESET_HIGH = 0
PORT Ext_Reset_In = sys_rst_s
PORT Slowest_sync_clk = sys_clk_s
PORT Chip_Reset_Req = C405RSTCHIPRESETREQ
PORT Core_Reset_Req = C405RSTCORERESETREQ
PORT System_Reset_Req = C405RSTSYSRESETREQ
PORT Rstc405resetchip = RSTC405RESETCHIP
PORT Rstc405resetcore = RSTC405RESETCORE
PORT Rstc405resetsys = RSTC405RESETSYS
PORT Bus_Struct_Reset = sys_bus_reset
PORT Dcm_locked = dcm_0_lock
END
BEGIN plb_v34
PARAMETER INSTANCE = plb
PARAMETER HW_VER = 1.02.a
PARAMETER C_DCR_INTFCE = 0
PARAMETER C_EXT_RESET_HIGH = 1
PORT SYS_Rst = sys_bus_reset
PORT PLB_Clk = sys_clk_s
END
BEGIN opb_v20
PARAMETER INSTANCE = opb
PARAMETER HW_VER = 1.10.c
PARAMETER C_EXT_RESET_HIGH = 1
PORT SYS_Rst = sys_bus_reset
PORT OPB_Clk = sys_clk_s
END
BEGIN plb2opb_bridge
PARAMETER INSTANCE = plb2opb
PARAMETER HW_VER = 1.01.a
PARAMETER C_DCR_INTFCE = 0
PARAMETER C_RNG0_BASEADDR = 0x40000000
PARAMETER C_RNG0_HIGHADDR = 0x7fffffff
PARAMETER C_NUM_ADDR_RNG = 1
BUS_INTERFACE SPLB = plb
BUS_INTERFACE MOPB = opb
END
BEGIN opb_uartlite
PARAMETER INSTANCE = RS232_Uart_1
PARAMETER HW_VER = 1.00.b
PARAMETER C_BAUDRATE = 115200
PARAMETER C_DATA_BITS = 8
PARAMETER C_ODD_PARITY = 0
PARAMETER C_USE_PARITY = 0
PARAMETER C_CLK_FREQ = 100000000
PARAMETER C_BASEADDR = 0x40600000
PARAMETER C_HIGHADDR = 0x4060ffff
BUS_INTERFACE SOPB = opb
PORT RX = fpga_0_RS232_Uart_1_RX
PORT TX = fpga_0_RS232_Uart_1_TX
END
BEGIN plb_bram_if_cntlr
PARAMETER INSTANCE = plb_bram_if_cntlr_1
PARAMETER HW_VER = 1.00.b
PARAMETER c_plb_clk_period_ps = 10000
PARAMETER c_baseaddr = 0xffff0000
PARAMETER c_highaddr = 0xffffffff
BUS_INTERFACE SPLB = plb
BUS_INTERFACE PORTA = plb_bram_if_cntlr_1_PORTA
END
BEGIN bram_block
PARAMETER INSTANCE = plb_bram_if_cntlr_1_bram
PARAMETER HW_VER = 1.00.a
BUS_INTERFACE PORTA = plb_bram_if_cntlr_1_PORTA
END
BEGIN dcm_module
PARAMETER INSTANCE = dcm_0
PARAMETER HW_VER = 1.00.a
PARAMETER C_CLK0_BUF = TRUE
PARAMETER C_CLKFX_BUF = TRUE
PARAMETER C_CLKFX_DIVIDE = 1
PARAMETER C_CLKFX_MULTIPLY = 3
PARAMETER C_CLKIN_PERIOD = 10.000000
PARAMETER C_CLK_FEEDBACK = 1X
PARAMETER C_DFS_FREQUENCY_MODE = HIGH
PARAMETER C_DLL_FREQUENCY_MODE = LOW
PARAMETER C_EXT_RESET_HIGH = 1
PORT CLKIN = dcm_clk_s
PORT CLK0 = sys_clk_s
PORT CLKFX = proc_clk_s
PORT CLKFB = sys_clk_s
PORT RST = net_gnd
PORT LOCKED = dcm_0_lock
END
BEGIN plb_bram_if_cntlr
PARAMETER INSTANCE = plb_bram_if_cntlr_2
PARAMETER HW_VER = 1.00.b
PARAMETER c_baseaddr = 0x00000000
PARAMETER c_highaddr = 0x00003fff
BUS_INTERFACE SPLB = plb
BUS_INTERFACE PORTA = plb_bram_if_cntlr_2_PORTA
END
BEGIN bram_block
PARAMETER INSTANCE = plb_bram_if_cntlr_2_bram
PARAMETER HW_VER = 1.00.a
BUS_INTERFACE PORTA = plb_bram_if_cntlr_2_PORTA
END
BEGIN opb_gpio
PARAMETER INSTANCE = dip1
PARAMETER HW_VER = 3.01.b
PARAMETER C_GPIO_WIDTH = 4
PARAMETER C_IS_BIDIR = 0
PARAMETER C_ALL_INPUTS = 1
PARAMETER C_BASEADDR = 0x40020000
PARAMETER C_HIGHADDR = 0x400201FF
BUS_INTERFACE SOPB = opb
PORT GPIO_in = DIP
END
BEGIN opb_gpio
PARAMETER INSTANCE = push1
PARAMETER HW_VER = 3.01.b
PARAMETER C_GPIO_WIDTH = 5
PARAMETER C_IS_BIDIR = 0
PARAMETER C_ALL_INPUTS = 1
PARAMETER C_BASEADDR = 0x40000000
PARAMETER C_HIGHADDR = 0x400001FF
BUS_INTERFACE SOPB = opb
PORT GPIO_in = PUSH
END
BEGIN my_led
PARAMETER INSTANCE = my_led_0
PARAMETER HW_VER = 1.00.a
PARAMETER C_BASEADDR = 0x7d800000
PARAMETER C_HIGHADDR = 0x7d8001ff
BUS_INTERFACE SOPB = opb
PORT LED = fpga_0_LEDs_4Bit_GPIO_d_out
END
BEGIN opb_timer
PARAMETER INSTANCE = delay
PARAMETER HW_VER = 1.00.b
PARAMETER C_BASEADDR = 0x41C00000
PARAMETER C_HIGHADDR = 0x41C001FF
PARAMETER C_ONE_TIMER_ONLY = 1
BUS_INTERFACE SOPB = opb
PORT Interrupt = timer1
PORT CaptureTrig0 = net_gnd
END
BEGIN opb_intc
PARAMETER INSTANCE = opb_intc_0
PARAMETER HW_VER = 1.00.c
PARAMETER C_BASEADDR = 0x41200000
PARAMETER C_HIGHADDR = 0x412001FF
BUS_INTERFACE SOPB = opb
PORT Intr = timer1
PORT Irq = interrupt
END