About this lab
This lab is built on the
first ML300-PPC405 lab. The primary goal is to introduce is to basic
interrupt concepts in the ppc405 environment. For this purpose, we will
add an interrupt controller and a programmable timer to the previous
project. Most of our discussion in this lab will be centered at the
software issues and development, more than the hardware, since we developed
the basics in the first lab.
All the files are provided
and the process of creation of the system is explained with detail.
Several issues will be solved through the tutorial and references will
be made to several Xilinx's documents. Please refer to the "links"
section of this site to get the documents or links to them.
A printable version of this
tutorial is available here.
The final files for this tutorial are available here.
System requirements
This lab was developed using
EDK 3.2.2 (the latest version up to now; Oct. 18), on a W2K Workstation
and the ML300 development platform. The files provided respond to these
specifications, however, the tutorial is meant to be easy to migrate
to another development platform or future (and past) versions of EDK.
If you find yourself in that situation and you find any trouble, please
contact us. Also, if you success in migrating this tutorial, please
send us your comments and anything you feel can be useful for us to
improve this lab.
Think about working on a
PIII 512Mb RAM at minimum. Also take in consideration that your workstation
needs a parallel port (to configure the FPGA), a serial port (to make
the connection with the hyperterminal) and a PS2 port (to power up the
parallel IV cable). Most laptops don't have these ports anymore.
Some assumptions made
We did some assumptions in
writing this tutorial. First of all, we are assuming you do have some
basic knowledge on C, embedded systems, microprocessors, and VHDL. This
save us the need in writing some details, but again, if you find any
thing that you think should be explained in more detail, let us know!!.
System Description
The specification of our
system is based on the system we built in the first ML300-PPC405 lab.
We will detail the additions to that project in the following sections:
Adding a Timer to the system
The first step is to add
a timer to our first simple project.
There different possibilities
to this:
a.- Fixed Interval Timer
(FIT_TIMER). As the name implies this is a peripheral that generates
as strove signal at fixed intervals and is not attached to any bus.
This is a small core, but it doesn't provide us with too much flexibility.
b.- OPB Timebase WDT. The
TBWDT (TimeBase WatchDog Timer) is a peripheral that attaches to the
OPB bus and basically provides a watchdog and a free running timebase
counter. So, this is a strong possibility.
c.- OPB Timer/Counter: This
is a more general core, a counter attached to the OPB. We will go for
this one. If you decide to change it and use any of the other modules,
the software changes are not complicated. We will try to cover that
in the following sections.
The final structure of the
system and it address map will be at follows:

Figure 1. System Block Diagram
The memory map is as shown
is the next table:

Taking as starting point
our first lab we can add the missing modules; go to XPS Add/Edit Cores
and add the core "opb_timer" and configure its addresses as
is shown in figure 2.

Figure
2. Adding the timer to the system
Take in consideration
that a bigger memory map space allocated to any core; will reduce the
FPGA resources required for decoding the address. A tight choice will
increase the number of FPGA resources required for implementation and
may adversely affect the maximum operating frequency of the system.
Now let add the connection to the bus and the necessary ports as shown
in figure 3 and 4.
Figure
3. Adding the bus connections
Figure
4. Adding ports
Here is something interesting.
This is a special case, for the opb_intc component; the interrupt vector
will be a concatenation of the locally defined interrupt signals and/or
external interrupts. The position of the interrupt signal defines the
priority. So, to add the interrupt signal of our timer to the interrupt
controller we need to change the port as shown in figure 5.
Figure
5. Interrupt ports
No special parameters need
to be setup this time. Well, this is about it on the hardware side;
by clicking "Ok", XPS will show you the modified system. As
before, we will generate the netlist by going to Tools/Generate Netlist
in the XPS interface. Since the *.ucf file have not really change with
respect to our first system, we can also proceed to the generation of
the bitstream.
Developing the Software
Design
As before, we need to specify
the driver level for the core we added, we will use level 1. What is
new for this project is that we will work with interrupts; that's why
we need to configure the interrupt handling routine. Check figure 6.
The interrupt parameter will not be enable if the interrupt pin of the
core is not connected.
Figure
6. Configuring Timer options.
Let's check some basics:
When working with peripherals, there are three principal I/O techniques:
programmed I/O, in which I/O occurs under the direct and continuous
control of the program requesting the I/O operation; interrupt-driven
I/O, in which a program issues an I/O command and then continues to
execute, until it is interrupted by the I/O hardware to signal the end
of the I/O operation; and direct memory access (DMA), in which a specialized
I/O processor takes over control of an I/O operation to move a large
block of data [1].
Our timer doesn't really need to transfer data, but still there are
two possibilities; a programmed or polled driven timer or a interrupt-driven
timer. We will work with interrupt since it's the main point of this
lab.
The C code for this lab is provided. Note that there is nothing really
new on it since it's based on the first lab. What's new is the interrupt
routine and the steps required to habilitate the interrupts and configure
the timer.
The steps to enable the interrupts are standard in the sense that they
probably won't change in the context of another program. The last three
steps; XExc_Init() to setup the interrupt vector table; XExc_RegisterHandler()
to register an exception handler for a specific exception; and XExc_mEnableExceptions()
to enable the interrupts are necessary and explained in Chapter 28 of
the EDK Documentation: Stand-Alone Board Support Package. The header
file xexception_l.h for the exception handling API can be find in /ppc405/code/include
in your project directory after you compile the libraries.
The C code provide was built on the examples provided with the drivers.
Take a look at \EDK\sw\iplib\drivers\ . You will find a directory for
each core. Look at tmrctr_v1_00_b\examples for instance; here you will
find examples for the timer core. As we discussed earlier, the timer
can be used as a polled-driven peripheral or an interrupt-driven peripheral.
There is also a xtmrctr_low_level_example to describe timer instructions
when you work with level 0 drivers.
Let's go back to our code. Every line is documented and it keeps a very
close relation with the examples provided with the drivers. The code
will display a "hello world" type message in the hyperterminal
and it will also display a warning each time an interrupt occurs. The
timer is setup to start counting at 0x1000000 in a countdown direction
til zero. At zero the counter will raise an interrupt and reset its
count to 0x1000000 and so on.
Well, now lets compile our code and add it to the bitstream by going
in XPS to Tools/ Compile Program Sources and Tools/Update Bitstream.
Careful! Check that the size of your program doesn't exceed the amount
of memory we programmed in our FPGA. Now use the same procedure as before
to program the board.
Debugging the program
The program will work, but
still, it's a good idea to take a look at what's happening in the processor
when handling an interrupt. In XPS go to Tools/XMD to open XMD. A windows
as shown in figure 7 will open up.
Figure
7. XMD window
Check the register of the timer and the interrupt controller just to
see have what you put in C code has been reflected in the configuration
of the peripherals:
% mrd 0x60008100 8
to read 8 memory positions
from the base address of the timer, check the values of the register
with the datasheet of the timer and verify it with the values you configure
in the C code. Here are some question for you to think about: Is the
timer running? Remember that the processor is stopped and waiting for
your instructions. Has the timer an interrupt raised right now?
% mrd 0x6000A200 8
to read 8 memory positions
from the base address of the interrupt controller. Here are some more
questions: Has the interrupt controller pending interrupts to attend?
Check the values in the registers and compare it with the datasheet
to figure out what is happening with the interrupt controller.
Now go to Tools/Software Debugger in XPS. A window similar to figure
8 will open up. Go
to "Run/Connect to Target" to connect the debugger to the
PowerPC405 processor.

Figure 8. Software debug window
Once you are connected, check the stack and local variables. Try to
understand at what point on the program you are. Then go one step further
in the program and check how the variables are changing and how the
interrupt is handled. Here are some questions for you, when the interrupt
happens, do you go directly to your timer interrupt handling routine?
What's the first step in handling the interrupt?. The software debugger
should help you to figure this out.
By now the project is running,
our hyperterminal console should look as shown in figure 9.

Figure
9. Hyperterminal view of the project
Our first interrupt based
project is up and running. We'll use this lab to build the next lab
in the sequence, a little bit more complex.
References:
[1] Computer Organization
& Architecture, Designing for Performance; Stallings, 6th edition.
Disclaimer:
This document, the contents
and the sample code, is provided AS IS without any expressed or implied
warranty. By providing this design, code, or information as one possible
implementation of this feature, application or standard, we are not
making representation that this implementation is free from any claims
of infringement, and you are responsible for obtaining any rights you
may require for your implementation.