CSE467-Lab 4


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


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.


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

Putting it Together

  1. Start up Xilinx Platform Studio (XPS). You can find it at:
    Start->Programs->Xilinx Embedded Development Kit 6.2->Xilinx Platform Studio.

  2. Start a new project
    1. File->New Project->Platform Studio...

    2. 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.

    3. The target device should be:
      Architecture Device Size Package Speed Grade
      virtex xcv1000 bg560 -6

    4. At this point, your the dialog should look mostly like this:

    5. Hit OK

    6. Hit Yes to start with an empty MHS file

  3. 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.
    1. Select Project->Add/Edit Cores... (dialog)
    2. Add cores and change their settings so you end up with a screen like the following: (pay careful attention to the memory addresses)

  4. 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).

    1. Select the Bus Connections tab
    2. 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.
    3. Add a opb_v20_v1_10_b bus, and rename it to the_opb.
    4. Now, click in the table to select the masters and slaves of the busses.
    5. You should now have a screen that looks like this:

  5. 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.
    1. Select the Ports tab.
    2. Add all the ports that end with Clk.
    3. Add all the ports that end with Rst.
    4. 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).
    5. Rename the nets so that you have a screen that looks something like this:

  6. 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.
    1. Select the parameters tab.
    2. From the dropdown box, select the_gpio
    3. Select the C_GPIO_WIDTH parameter and add it.
    4. Change the C_GPIO_WIDTH parameter to be 1.
    5. You should now have a screen that looks like this:

  7. Add the code.
    1. Save the blinker.c file to your $PROJECT/code directory. Note that you'll probably have to create the directory.
    2. 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
  8. 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.)

  9. Compile the system.
    1. 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.

  10. Download the program using iMPACT
    1. Start iMPACT (Start->Programs>Xilinx ISE 6->Accessories->iMPACT)
    2. Select Configure Devices and then Slave Serial Mode
    3. 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.
    4. Right click on the chip icon and select download.

  11. If all has gone well, you should see the AJ2 LED blinking.

  12. How much of the Vertix 1000 did your implementation use?  Be ready with an answer for the TA.

  13. 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


  1. Create a new project in XPS, but this time, call it fader.xmp
  2. 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.
  3. 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
  4. 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.
  5. All the parameters can be left as default
  6. Copy fader.ucf into your project's data directory.
  7. Copy the skeleton fader.c file into your project's code directory (remember, you'll probably have to create this directory)
  8. Add the fader.c file to your project and open it up.
  9. 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).
  10. 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.
  11. 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

  1. Start up XPS and create a new platform studio project.

  2. Now that XPS has set up the directories for your project close it.

  3. 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.

  4. 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.

  5. Start XPS back up and open your project. You can do this simply by double-clicking your <project>.xmp file.

  6. 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.

  7. Add the following peripherals using the Tools->Add/Edit cores dialog. The exact addresses and names are not important as long as:
    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

  8. Setup the bus connections. Just like last time, you'll want to use: Rename the busses to meaningful names, and connect all the peripherals to their corresponding busses.

  9. Connect up the ports.
    You'll want to add:
  10. 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

  11. 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.
  12. 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.
  13. Connect the cpu's INTERRUPT port to the interrupt controller's Irq port. Make sure they're internal.
  14. Connect the interrupt controller's Intr port to the audio's Interrupt port. Make sure they're internal.
  15. OK out of the dialog and now add the code files. Do the following before compiling:
  16. 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.
  17. 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:

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:

        1. Go into the add/edit cores dialog, change the High Address of both lmb_bram controllers to be <ramsize> - 1
        2. 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):

      1. 440.00 (A4)
      2. 493.88 (B4)
      3. 554.37 (C#5)
      4. 587.33 (D5)
      5. 659.26 (E5)
      6. 739.99 (F#5)
      7. 830.61 (G#5)
      8. 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:

      1. 523.25 (C5)
      2. 659.26 (E5)
      3. 783.99 (G5)
      4. 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