top of page
Writer's pictureAngelo Jacobo

UberDDR3 + MicroBlaze (Part 1) - Post #7

Until now, integrating UberDDR3 into your project meant manually adding it at the top level of your Verilog design. But wouldn’t it be easier if you could add UberDDR3 to the Vivado IP catalog, making it available in the Block Design to connect seamlessly with other IPs like MicroBlaze?


In this blog, I'll walk you through how to do exactly that. We’ll start by adding UberDDR3 to the Vivado IP catalog. From there, we'll connect UberDDR3 to MicroBlaze then implement a "Hello World" program to test our integration. Let’s get started!


Table of Contents:


I. Integrate UberDDR3 into the Vivado IP Catalog

Our first goal is to integrate UberDDR3 into the IP catalog and make it available for instantiation in the block diagram. The UberDDR3 repository already includes the necessary files for Vivado to recognize UberDDR3 as a custom IP block. Here are the steps:


1. Retrieve the UberDDR3 repository by git cloning:

Or if you do not have git installed, go to my GitHub repo:

then click the <> Code button and then Download Zip. Unzip this file after downloading.


2. Create a new Vivado project, then click on IP Catalog:


IP Catalog tab will open, right-click on Vivado Repository > Add repository.


Browse for the UberDDR3 repository which you just cloned on step 1:


Once you are back on the IP Catalog tab, check under User Repository > UserIP and you should find the new custom IP uberddr3_axi_v1_0. You should also see the following details:


Now, we are ready to instantiate UberDDR3 on the block design!


II. Demo Project 1: Hello World

The MicroBlaze IP in Vivado is a small, customizable soft processor core. You can easily set it up in the Vivado Block Design and use the full automation capability of Vivado to configure the entire system with other peripheral IPs. MicroBlaze is often paired with Memory Interface Generator (MIG) to access external memory, like DDR3 or DDR4, allowing for a much larger memory capacity than using the FPGA's block RAM. This setup is ideal for embedded applications requiring flexible, scalable memory resources.


But why use MIG when you have UberDDR3?! For this demo, we’ll set up UberDDR3 as both the instruction and data memory for MicroBlaze instead of MIG, and then create a simple program that displays "Hello World" over UART. For this blog post, I will be using my very dear ArtyS7-50 FPGA board. Let’s get started!


II.I Steps for Creating Design on Vivado:

1. After following the previous steps of adding UberDDR3 on the Vivado IP catalog, click on Create Block Design. Configure design name accordingly, for this project I named it as artys7_50_bd.


2. Click on "+" symbol and search for MicroBlaze:


Run Block Automation will show up, click on it then set-up the Local Memory to 8KB and Cache Configuration to 32KB. A small local memory is sufficient since the main program will run on the DDR3 memory:


3. The block diagram will look like the one below. Notice that the input of Clocking Wizard is named CLK_IN1_D which means it uses a differential clock input, but Arty S7 only has a single-ended clock so we have to modify this. Also, UberDDR3 requires some clock input from this clock wizard.


Click on the Clocking Wizard IP:


On the Clocking Options tab, modify the source of the primary clock to Single ended (clock capable pin):


On the Output Clocks tab, enable 4 clock outputs with the following settings:

  • controller_clk = 83.33333 MHz

  • ddr3_clk = 333.33333 MHz

  • ref200_clk = 200 MHz

  • ddr3_clk_90 = 333.33333 MHz, 90° phase shift


4. Click on "+" icon then search for the UberDDR3 IP which we just integrated on the Vivado IP Catalog earlier.


Click on the block uberddr3_axi_0, customize the following settings accordingly:


  • The DDR3 RAM of ArtyS7-50 can run at a maximum clock input of 333.33333 MHz (or 3000 ps for the DDR3 Clock Period). Since UberDDR3 is a 4:1 memory controller, the controller user interface will run at 1/4 of DDR3 clock thus 83.33333 MHz (or 12000 ps for the Controller Clock Period).

  • Row, Column, and Bank bits can be left as is (though there are some DDR3 with Row Bits of 15 so due diligence must be done by checking on the specification of your DDR3 chip). For ArtyS7-50, these three parameters can be left as is.

  • The DDR3 used on ArtyS7-50 is an x16 ddr3 thus Byte Lanes of 2.

  • ECC Enable can just be set to zero (ECC disabled). Possible options are:

  • There are three check boxes:

    • Skip Internal Test = Make sure to check this if UberDDR3 will be used with MicroBlaze. The built-in self-test of UberDDR3 takes more than 2 seconds and that long start-up can cause MicroBlaze to fail booting up.

    • ODELAY Supported = Check this only if the DDR3 is connected to the High Powered (HP) bank of your FPGA which supports ODELAY block. But for ArtyS7-50 which uses Spartan 7, there is no ODELAY block.

    • Micron Simulation = This should only be checked during simulations, but since we want to implement UberDDR3 straight to hardware, make sure to not check this.


Once you are done customizing the settings, click OK.


5. Run connection automation then check All Automation. Under uberddr3_axi are the clock inputs required by UberDDR3. As shown below, we have to modify each clock to be connected to the corresponding clock output from the Clocking Wizard.


i_ddr3_clk must be connected to /clk_wiz_1/ddr3_clk (333 MHz):


i_ddr3_clk_90 must be connected to /clk_wiz_1/ddr3_clk_90 (333 MHz):

i_ref_clk must be connected to /clk_wiz_1/ref200_clk (200 MHz):


Click OK to run connection automation. After that, Run Connection Automation will show up again but this time it will automate connecting the AXI slave interface of UberDDR3 to the AXI master interface of MicroBlaze (with AXI SmartConnect as the bridge IP):


6. After running connection automation, it should look like the following:

Now, we have to modify some connections here. For example as shown below, ext_reset_in input port of Processor System Reset is connected to a separate input pin reset_0. Remove this and just reconnect it to the already existing reset input pin:

Next, i_rst_n input port of uberddr3_axi_0 should then be connected to peripheral_aresetn output port of Processor System Reset:

Next, notice how the ddr3 output port of uberddr3_axi_0 has no connections. Right click on this port then Make External. This will bring this port to the top-level module:


Lastly, on the External Interface Properties window, change the name of this new port connection to simply "ddr3" (which was previously "ddr3_0") to make it easier to map on the XDC constraint file which we will talk about later:


7. We will now add some more peripheral IPs on this design. First is the AXI Uartlite then second is the AXI Timer. AXI Uartlite is required since the Hello World will be displayed via the UART serial line. AXI timer is required for the next demo project which is the Dhrystone Test.


Run connection automation for these two newly added IP peripherals:


Our system is now complete, and it should like the following:


Click on Validate Design, there should be no error:



8. We now have to add the constraint file for the IO pins. Looking on the block diagram, we have 4 main pins for this project:

  • ddr3_clk

  • reset

  • ddr3 bus

  • usb_uart bus


Now, if we look on the Board tab (on the right), we can see that the DDR3 Clock, System Reset, and USB UART were already marked by the tool. This implies that we do not have to include these ports in the constraint file since the tool already knows where and how to constrain them.


However, notice that the DDR3 SDRAM is not marked which means the tool were not able to recognize the ddr3 port on the block diagram! This makes sense since normally the Memory Interface Generator is used and connected to the ddr3 port interface. Now that we used a different controller (UberDDR3), the tool was not able to recognize the ddr3 port.


But no worries, this is not a big problem at all. We just have to create a constraint file for the ddr3 ports. Add a new constraint file by clicking on the "+" icon then Add or create constraints.


On the empty XDC file, copy paste the following constraints for ddr3 pins of ArtyS7-50:


9. We are now almost done! Under the Sources tab, right click on the block diagram name then Create HDL Wrapper:


Then click on Generate Bitstream:


Wait for some time then it should be completed successfully:


We can now export this design by clicking on File > Export > Export Hardware:


Make sure to include bitstream and set the XSA file name:


II.II Steps for Implementing "Hello World" Program in Vitis:

1. Open Vitis from Vivado by clicking on Tools > Launch Vitis IDE.



Choose your desired workspace. My preference is to create the workspace under the Vivado project (artys7_50):


Click on Create Application Project:


Switch to Create a new platform from hardware (XSA) then browse for the XSA file which we just exported from Vivado earlier:


Provide your desired project application name, in my case I named it artys7_hello_world:

For the template, choose Hello World:


2. Once the directory and files are created, open the linker script lscript.ld under src folder. Notice how it was able to recognize uberddr3_axi_0_ddr3_mem as a memory region. The memory region of all sections is already automatically mapped to UberDDR3 which is exactly what we want!


3. Click on the hammer icon to build the project. Wait until it is finished:


At this moment, make sure to plug-in the ArtyS7-50 board on your computer via USB. Right click on the project application > Debus As > Launch Hardware. This will program the FPGA board and switch the Vitis window to Debugging.


4. On the debug window, click on Vitis Serial Terminal then set-up the serial port accordingly. The AXI Uartlite is set to baud rate of 9600 by default:


You can then click on the step-over icon to advance the program by line, notice how the green highlight on Vitis moves down line by line. By the time you reached return 0 of the code, the serial terminal should have already printed Hello World:


Done, congratulations! We were now able to successfully run MicroBlaze with UberDDR3!


IV. Conclusion

In this blog post, we learned how to set up the UberDDR3 controller in the AMD Vivado IP catalog, making it super easy to use with MicroBlaze. By following the steps, you can quickly add UberDDR3 to your block designs and take advantage of Vivado's handy automation features. This means you can work smarter when building your projects! With UberDDR3 now in the Vivado catalog, it’s easier than ever to create cool embedded applications with lots of memory using an open-source DDR3 memory controller!


That wraps up this post. Catch you in the next blog post for part where we will dive into running a Dhrystone test program and building a simple Ethernet project, both powered by MicroBlaze with UberDDR3!




127 views

Comments


Computer Processor

Subscribe to Our Newsletter

Thanks for submitting!

bottom of page