DE0-Nano | NiosII with SDRAM

This is a little upgrade to the NiosII core I built before in this tutorial:

DE0-Nano | NiosII untethered

It adds support for the 32MB SDRAM chip to the core.

I will quickly go through the steps of

    • adding a SDRAM controller to the NiosII core

    • using a PLL core to generate a phase shifted clock for the RAM

    • moving the Hello World program into the new memory and allocating a 'huge' chunk of memory

We are starting off with the previously built core so you can either first run through the NiosII untethered tut in a new folder or copy the previously created folder to a new location and rename it.

Once that is done you can continue here...

This is our starting point. The previously built NiosII core:

Beefing up the hardware

SDRAM controller

    • back in Quartus II open sopc builder again

    • and add an SDRAM controller (Memories and Memory Controllers/SDRAM/SDRAM Controller)

    • presets: custom

    • data width = 16 bits

    • row width = 13

    • column width = 9

    • If you don't plan to pipe video or some other bandwidth hungry task through it you can leave the rest on default. The next settings in green are optional tweaks to tickle a little more performance out of the chip. (I haven't actually run benchmarks to tell if it makes any difference)

  • under the Timing tab set CAS latency cycles to 2

  • Initialization refresh cycles = 8

  • Issue one refresh command every = 0.75 us

  • Delay after powerup =200us

  • t_rfc = 70ns

  • t_rp = 20ns

  • t_rcd = 20ns

  • t_ac = 6.5ns

  • t_wr = 14 ns

    • click finish

    • rename sdram_1 to sdram

    • select the cpu and click edit

    • set the interrupt and exception vectors to the sdram

    • click finish

PLL module

The SDRAM is an external component and has a few timing requirements that need to be addressed to play nice with our NiosII core. To make sure all the signals are stable on the clock edge we are going to feed a second clock signal into the SDRAM that sightly precedes the cpu clock. This can be done with a PLL element.

    • add an Avalon ALTPLL component ( PLL>Avalon ALTPLL )

      • general/modes:

      • change inclk0 input frequency to 50 Mhz

      • click next

      • Inputs/Lock:

      • uncheck "create an 'areset' input ..."

      • uncheck "Create 'locked' output

      • click next

      • Bandwidths/SS:

      • click next

      • Clock switchover:

      • click next

      • PLL Reconfiguration:

      • click next

      • Output Clocks:

      • clk c0:

      • check 'use this clock'

      • set "clock phase shift" to -3ns

      • click finish twice to exit the wizard

    • rename altpll_0 to shift_clk

    • Important!: The name of the component must be anything other then altpll ! Otherwise a sopc builder bug will prevent you from compiling the system. Something like:

    • "Error: Error: Node "c0" is missing source File: C:/Users/Florian/AppData/Local/Temp/alt5441_758227333335766729.dir/0004_sopcqmap/altpll.v Line: 228"

This creates a new clock with an output pin which we can later connect directly to the clock input of the SDRAM chip.

System ID

Since I skimmed over this component in the previous tutorial and to silence the continuous bickering of various tools we will quickly add a System ID component. It is actually useful to keep track of whether the BSP driver package currently used is still compatible with the hardware you are trying to run it on. And it's painless to do.

    • add a System ID Peripheral (Peripherals/Debug and Performance/System ID Peripheral)

    • click Finish

    • rename sysid_0 to sysid

    • click File>Refresh System (not sure if that's necessary but there is something strangely satisfying about it)

    • and then click Generate

    • save the system and click Exit to leave SOPC Builder

--

    • In the Project Navigator double click the mynios2.bdf file to open it in the schematic editor.

    • right click the nios symbol and select "Update Symbol or block" to see the new pins

    • drag select and delete all previously generated pins and wires connecting them

    • right click the nios symbol and select "Generate pins for symbol ports"

    • In my case the PLL generator actually created areset, locked and phasedone pins despite the fact that I explicitely unchecked those options. If you find those ports on your symbol delete the pins leading to them.

    • save and compile

Wiring up the SDRAM chip

Alright, so the SDRAM chip has an awful abundance of pins that need to be connected to the Nios.

Just as in the previous tut open the Pin Planer and connect the following pins. The phase shifted clock c0 from the PLL module is connected to the clock of the ram.

    • Note, in case you find it tedious to use the (horrible) Pin Planner to connect those 39 pins manually, here's an alternative: locate the settings file mynios2.qsf in the project folder and open it in a text editor. Then copy/paste the sdram pin assignments into it. Then reopen the project. All the pins will now be assigned in the pin planer.

    • compile the project again

    • open up the Programmer window (Tools>Programmer) and if the sof file from the previous session is still selected delete it from the list or select File>New

    • add the new sof file to the list and upload it to the board

Adopting Hello_World

After all this it's a good idea to see if the processor we just build is is still functional. So let's upload our Hello_World and see if it still works. After that we'll make use of the newly available bulk of memory.

Eclipse ($#!*..!)

Now, at this point I would have loved to describe how to just use the hello_world project we copied from the previous tut. Unfortunately, I could not figure out how to do that. Apart from Eclipse's workspace concept and it's annoying habit of storing metadata all over the place it uses absolute paths for certain things. The bsp project does the same thing. So after an hour of trying to create new workspaces and importing the copied projects, tweaking settings and chasing environment variables I gave up. The hello_world project is recreated in like 3.5 minutes without all this pain. (Although it would still be interesting to know how to migrate a somewhat more complex project to a new folder).

    • go to your new project folder and delete the entire contents of the software subfolder

    • also delete the .metadata folder in the project root (this is where the workspace is stored, among other things)

    • Fire up NiosII Software Build Tools for Eclipse

    • switch the workspace to your new project (File > Switch Workspace...)

    • The workspace should be empty!

    • right click the Project Explorer and select New > NiosII Application and BSP from Template

    • under SOPC Information File name select your new DE0_NANO_SOPC.sopcinfo file

    • call the project hello_sdram and leave the project template set to Hello World

    • click Finish

    • copy paste the code from the previous tut into the file hello_world.c

    • #include <stdio.h>

    • #include "system.h"

    • #include "altera_avalon_pio_regs.h"

    • int main()

    • {


    • printf("Hello from Nios II on steroids (SDRAM) !\n");

    • int count = 0;

    • int delay;

    • while(1) {

    • IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, count & 0x01);

    • delay = 0;

    • while(delay < 200000)

    • delay++;

    • count++;

    • }

      • return 0;

    • }

    • Note that I changed the welcome message slightly to make sure we are seeing the output of the new program

    • ( If, instead of copying the previous tut, you walked through it and continued this SDRAM tut in the same folder with the same eclipse project you will have to regenerate the BSP project. Right click it and select NiosII > Generate BSP. This step is also required every time you change something about the hardware)

    • select Project > Build All

    • right click the hello_world project and select run as NiosII Hardware.

    • The program should now blink LED0 on the DE0-Nano board and print the welcome message into the console

malloc()

Finally, let's relocate our program into the SDRAM and allocate a large amount of memory (for a micro controller) as proof of concept .

    • open up the BSP Editor by right clicking the BSP project and selecting NiosII > BSP Editor...

    • Go to the Linker Script tab and in the Linker Section Name box change every linker region from onchip_memory2 to sdram

    • Add the following lines to the code:

#include <stdio.h>

#include <stdlib.h>

#include "system.h"

#include "altera_avalon_pio_regs.h"

int main()

{


printf("Hello from Nios II on steroids (SDRAM) !\n");

void *lots_of_memory = malloc(1024*1024*10); // lets allocate 10MB or memory

printf("malloc returned 0x%08lx\n", (alt_u32)lots_of_memory);

}

while(delay < 200000)

delay++;

count++;

while(1) {

IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE, count & 0x01);

delay = 0;

int count = 0;

int delay;

return 0;

}

    • This should produce an output like this:malloc() returned a valid pointer to a 10MB memory block.

    • If you want you can try to allocate 100MB in which case malloc will fail and return 0.

Useful links

Altera tutorial about the same thing, although instead of the ALTPLL module they are using an Altera University Program IP core called Clock Signals. Apparently this is bundled with QuartusII 11.1 but not by default available in 11.0.

ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Tutorials/Verilog/DE0-Nano/Using_the_SDRAM.pdf

Data sheet of the SDRam chip from ISSI. Note, there is a datasheet included on the DE0-Nano CD which is much more readable. This one is more recent but includes more irrelevant (for the DE0-Nano) information.

http://www.issi.com/pdf/42-45S83200D-16160D.pdf

Disclaimer

Other projects you might like