CSE467-Lab 4
Documents
Here are some documents relating to this lab:
Introduction to Microblaze
EDK introduction
EST introduction
IP guide
Drivers guide
Part 1- Microblaze blink and fade
Introduction
This is a simple Xilinx Platform Studio (XPS) project for the AFX BG560-100 proto board. This project illustrates the minimal amount of work necessary to produce a working Microblaze system.
This simple project will blink an LED at about 2Hz and will involve busy waiting for a delay, and then toggling the output of the LED.
Layout
Here is a block diagram of the the blinker system. Note that there is only one peripheral in addition to the Microblaze attached to the OPB bus. The OPB bus can handle an immense number of peripherals all sharing it, but this project only uses a single GPIO module.
Memory Map
The Microblaze uses memory mapped IO to talk to the OPB peripherals. The following is the map of the peripherals used in this project and their respective address mappings.
Device |
Base Address |
High Address |
Size |
Comment |
the_ram |
N/A |
N/A |
2KB |
Ram for the application |
the_cpu |
N/A |
N/A |
N/A |
Cpu core |
i_controller |
0x00000000 |
0x000007FF |
2KB |
Instructions ram controller |
d_controller |
0x00000000 |
0x000007FF |
2KB |
Data ram controller, note that it's range overlaps the instruction controller's |
the_gpio |
0xFFFF4000 |
0xFFFF40FF |
256B |
The general purpose IO for the LED |
Tidbits of Info
- You can find the source for the core drivers (functions for manipulating timers, general purpose IO, etc.) in C:\EDK\sw\XilinxProcessorIPLib\drivers
- You can find the documentation for cores in the upper right corner of the properties pane of the
Add/Edit Cores
dialog.
Putting it Together
- Start up Xilinx Platform Studio (XPS). You can find it at:
Start->Programs->Xilinx Embedded Development Kit 6.2->Xilinx Platform Studio.
- Start a new project
- File->New Project->Platform Studio...
- Select a location for your project. I'd suggest Z:\p467\first_microblaze\blinker.xmp. Later in this project there will be references to your project directory $PROJECTDIR If you choose the above location for your project the $PROJECTDIR will be Z:\p467\first_microblaze.
- The target device should be:
Architecture |
Device Size |
Package |
Speed Grade |
virtex |
xcv1000 |
bg560 |
-6 |
- At this point, your the dialog should look mostly like this:
- Hit OK
- Hit Yes to start with an empty MHS file
- Add the peripherals to your project. XPS comes with a large number of pre-made cores including timers, rams, general purpose io (gpio) modules, serial controllers, and a host of other cores.
- Select Project->Add/Edit Cores... (dialog)
- Add cores and change their settings so you end up with a screen like the following: (pay careful attention to the memory addresses)
- Setup the bus connections. The XPS systems are all very bus-centric. This means that you have a number of cores that communicate with each other over busses. This project utilizes two types of busses: Local Memory Bus (LMB) and OPB On-chip Peripheral Bus (OPB).
- Select the Bus Connections tab
- Add 2 lmb_v10_v1_00_a busses, and rename them to i_lmb and d_lmb by right-clicking on the label and selecting rename instance. These are the lmb busses that will be the interfaces to the ram for instructions and data, respectively.
- Add a opb_v20_v1_10_b bus, and rename it to the_opb.
- Now, click in the table to select the masters and slaves of the busses.
- You should now have a screen that looks like this:
- Setup the ports. These are the non-bus interfaces between components as well as nets (wires) that will be connected to physical pins on the device.
- Select the Ports tab.
- Add all the ports that end with Clk.
- Add all the ports that end with Rst.
- Add the port GPOI_IO from the the_gpio core. Make sure to change the range to [0:0] to say that there is only a single pin (for the LED).
- Rename the nets so that you have a screen that looks something like this:
- Setup the Parameters. There are many things you can customize about the cores. Most defaults are fine, but some you will have to change. The only thing you need to change for this project is the width of the_gpio. Note also that this is the window where you can find documentation on any of the cores in your design. There is a button in the upper right corner of this pane that will open the documentation for the selected component.
- Select the parameters tab.
- From the dropdown box, select the_gpio
- Select the C_GPIO_WIDTH parameter and add it.
- Change the C_GPIO_WIDTH parameter to be 1.
- You should now have a screen that looks like this:
- Add the code.
- Save the blinker.c file to your $PROJECT/code directory. Note that you'll probably have to create the directory.
- In XPS, on the left side of the screen, you'll find the tree for your project. Right click on the sources entry under the_cpu under System BSP. Select Add Files and browse to blinker.c
Now, you need to tell the project what nets to connect to physical pins on the device. This is done with a user constraints file (ucf). Download blinker.ucf and save it in your $PROJECT/data directory. (You should wire the chip enable to VCC for this lab, so that your SRAM is disabled.)
- Compile the system.
- Select Tools->Update Bitstream. This will compile all the vhdl, verilog, and c code that were created by XPS when you made your selections. This step will probably take several minutes.
There will be a large number of warnings that scroll by in the screen. Most of them are warnings about unused wires and nets. This is normal since we're not using all the available features of all the cores.
- Download the program using iMPACT
- Start iMPACT (Start->Programs>Xilinx ISE 6->Accessories->iMPACT)
- Select Configure Devices and then Slave Serial Mode
- When prompted for a file, select the bitfile: $PROJECT/implementation/download.bit You'll get a warning that the Startup Clock was changed to CClk. This is fine.
- Right click on the chip icon and select download.
- If all has gone well, you should see the AJ2 LED blinking.
- How much of the Vertix 1000 did your implementation use? Be ready with an answer for the TA.
- Now, change the blink pattern to blink, blink, off, blink, blink, blink, off..(sound familiar???) Demonstrate this to the TA for check off, and report your utilization findings.
Part 2- Pulse Width Modulation with the Microblaze
NOTE: There appears to be an error in the documentation regarding the period and duty cycle settings for the PWM. The PWM_PERIOD and PWM_HIGH_TIME values for when UDT=1 are listed under UDT=0 and vice versa. Instead, the values should be:
UDT = 1 (count down) |
PWM_PERIOD = (TLR0 + 2) * OPB_CLOCK_PERIOD
PWM_HIGH_TIME = (TLR1 + 2) * OPB_CLOCK_PERIOD |
UDT = 0 (count up) |
PWM_PERIOD = (MAX_COUNT - TLR0 + 2) * OPB_CLOCK_PERIOD
PWM_HIGH_TIME = (MAX_COUNT - TLR1 + 2) * OPB_CLOCK_PERIOD |
Steps
- Create a new project in XPS, but this time, call it fader.xmp
- Create all the same peripherals as in Part 1, except that instead of the opb_gpio component, make an opb_timer component and name it the_timer.
- In the Bus Connections tab, set everything up the way it was in the previous lab, except that again, substitute the timer for the gpio
- In the ports tab, add the PWM0 port to the list of ports and give it the net name "led". You can name it something else if you'd like, but then you'll have to change it in the ucf file.
- All the parameters can be left as default
- Copy fader.ucf into your project's data directory.
- Copy the skeleton fader.c file into your project's code directory (remember, you'll probably have to create this directory)
- Add the fader.c file to your project and open it up.
- At this point, you'll notice a number of comments marked TODO: Follow those instructions to add the necessary parts to the source. The documentation you'll want to look at are the timer pdf (found in the C:\EDK\hw\XilinxProcessorIPLib\pcores\opb_timer_v1_00_b\doc directory) and the low-level timer driver header file (found in the C:\EDK\sw\XilinxProcessorIPLib\drivers\tmrctr_v1_00_b\src directory).
- Once you've updated the code, update the bitstream, and download the download.bit file to your board. If all went well, you should see the led pulsating.
- If you're feeling particularly ambitious, add a second timer and use it to generate interrupts for you so that the code does not just waste cycles while it's waiting to change the pwm duty cycle.
If you really get stuck, we'll add a working solution here later in the week . (You will have to make a new project and add these files.)
Part 3- Generating Sound with the Microblaze and CSE AUDIO board
Now that you have built a simple project with XPS, it's time to
make a slightly more complicated one. In this lab, you will interface
with the audio board to output a 440Hz ('A' below middle 'C') sine wave
using a table driven oscillator.
The Setup
The setup is going to be similar to the previous lab, however, it
will use a custom core as well as an interrupt controller.
The Steps
- Start up XPS and create a new platform studio project.
- Choose whatever name you'd like, and remember that the
directory containing the .xmp file will be referred to as your project
directory and the name of the .xmp file will be referred to as your
project name.
- Set your target device as before:
Architecture |
virtex |
Device Size |
xcv1000 |
Package |
bg560 |
Speed Grade |
-6 |
- Now that XPS has set up the directories for your project close
it.
- Unzip the audio controller
core and put the pcores directory in your project directory. This
directory contains the verilog, documentation, and meta data for the
opb_audio_controller core. When XPS generates the list of available
cores for the "add/edit cores" dialog, one of the places it searches is
the $PROJECT/pcores directory, so now that you've put the core there,
it will automatically find it.
- Unzip the starter code. Put the
code directory in your project directory. Rename the .ucf file so that
it matches your project name and put it in the data directory inside
your project directory.
- Start XPS back up and open your project. You can do this simply
by double-clicking your <project>.xmp file.
- Confirm that you put the audio controller core in the right
place by opening up the add/edit cores dialog and making sure that
opb_audio_controller is in the list of available cores.
- Add the following peripherals using the Tools->Add/Edit cores
dialog. The exact addresses and names are not important as long as:
- none of the adresses overlap (except for the two
lmb_bram_if_cntlr's)
- The last two hex digits of the base addresses are 00.
- The last two hex digits of the high addresses are FF.
- The opb_audio_controller is named audio since there are
entries in the .ucf file that assume that it is.
- Use version 1.00.b of int_ctrl instead of 1.00.c.
Hardware |
Instance Name |
Base Address |
High Address |
bram_block |
the_ram |
n/a |
n/a |
lmb_bram_if_cntlr |
i_ctrl |
0x00000000 |
0x000007FF |
lmb_bram_if_cntlr |
d_ctrl |
0x00000000 |
0x000007FF |
microblaze |
the_cpu |
n/a |
n/a |
opb_audio_controller |
audio |
0xFFFF4000 |
0xFFFF40FF |
opb_intc |
int_ctrl |
0xFFFF4100 |
0xFFFF41FF |
- Setup the bus connections. Just like last time, you'll want to
use:
- Two lmb_v10_v1_00_a busses. One for the instruction
controller and one for the data controller.
- An opb_v20_v1_10_b bus.
Rename the busses to meaningful names, and connect all the peripherals
to their corresponding busses.
- Connect up the ports.
You'll want to add:
- All of the audio controller ports.
- All of the interrupt controller (intc) ports.
- The INTERRUPT port of the microblaze
- All the rest of the ports whose name ends with clk or
rst.
-
On on the audio controller ports, make sure that you have
the following connections (Except for XTAL_CLK, they should all default
to these values) :
Port |
Net Name |
XTAL_CLK |
xtal_clk |
MCLK |
audio_MCLK |
BICK |
audio_BICK |
LRCK |
audio_LRCK |
SDTI1 |
audio_SDTI1 |
SDTI2 |
audio_SDTI2 |
SDTI3 |
audio_SDTI3 |
SDTI4 |
audio_SDTI4 |
SDTO |
audio_SDTO |
PDN |
audio_PDN |
- Connect up all the clock nets on a net named sys_clk. To
do
this, select all of the ports (control-click) that end with clk except
for XTAL_CLK and hit the Connect button. Choose a net name (sys_clk is
fine, but it doesn't really matter) and make the selected ports
Internal.
- Do the same for all the ports whose name ends with rst,
except make the selected ports external. The net should be named
sys_reset.
- Connect the cpu's INTERRUPT port to the interrupt
controller's Irq port. Make sure they're internal.
- Connect the interrupt controller's Intr port to the
audio's
Interrupt port. Make sure they're internal.
- OK out of the dialog and now add the code files. Do the following before compiling:
- Right click on "the_cpu" or whatever you named your microblaze in the EDK
- Choose "S/W Settings"
- Change opb_intc to include 1.00.b files instead of 1.00.c
- At this point, you should be able to build the system, and
it should generate a triangle wave on the left channel of the first
output. Plug some speakers into the OUT 1-2 jack and you should hear
the triangle wave. Alternatively, you can touch the tip of an
oscilloscope probe to either end of C11 (right next to the OUT 1-2
jack) and after hitting autoset, you should see a triangle wave on the
screen. Here is a tutorial on use of the oscilloscope, and here is the scope manual.
- Now, modify the code to output a sine wave at 440Hz
instead
of a triangle wave. I'd suggest a table driven oscillator. A few pieces
of information you'll want:
- The sample rate of the codec is 43.4kHz. Use a table
length of 256 entries.
- The Microblaze has no floating point operations. If
you
use floating point, the compiler will emulate it, however, it will be
extremely slow, so you should not use floating point.
- The Microblaze does not have a hardware multiplier, so
multiplies are done in software. As a result, they are very slow. You
probably have about enough time between samples to do about 2
multiplies, maybe 3.
- Don't even think about doing a divide by a number
other
than a power of 2 (bit shift).
- The audio codec takes 24-bit signed numbers, centered
at
0. This means that:
- The highest value it can receive is 2^23 - 1, or
8388607, or 0x007FFFFF.
- The lowest value it can receive is -(2^23) or
-8388608, or 0xFF800000.
- Basic two-step program for table-driven sine generation (see Wednesday's lecture notes for more information):
phase_index = modL(previous phase + increment)
Output = amplitude * wavetable[phase_index]
increment = (TableLength * DesiredFrequency)/SampleRate
18. The block ram by default is only 2kBytes. Once you
implement
your table, you will likely use more than 2kBytes of memory. You can
check on your program's usage by going to Tools->Get Program Size.
dec is the total size in decimal, and hex is the total size in
hexadecimal. You can make ram in sizes of 2048, 4096, 8192, or 16384
bytes. You'll want to choose the smallest one that is larger than your
program. If your program is over 16k, you'll have to change your
program, since that's all the ram that's available on this chip, until we add in our external SRAM.
To change the size of ram:
- Go into the add/edit cores dialog, change the High Address of both lmb_bram controllers to be <ramsize> - 1
- In the Parameters tab, change the C_MEMSIZE parameter to be the new size
You should now have a system that outputs a sine wave. Demonstrate your output, and the resultant waveform on the oscilloscope, to a TA. Hand in your table-driven generator code printout.
19. Make your sine wave cycle through the following frequencies (200 ms. each):
- 440.00 (A4)
- 493.88 (B4)
- 554.37 (C#5)
- 587.33 (D5)
- 659.26 (E5)
- 739.99 (F#5)
- 830.61 (G#5)
- 880.00 (A5)
The musically inclined of you should recognize this as the A major scale. Demonstrate your output to a TA.
20. Output all 4 of the following 4 frequencies simultaneously:
- 523.25 (C5)
- 659.26 (E5)
- 783.99 (G5)
- 1046.5 (C6)
To do this, generate all 4 frequencies and send the average of
the 4
signals to the codec (add the 4 signals together and divide by 4).
The
musically inclined should recognize this as a C major chord. Demonstrate your output to a TA
bruceh@cs