Nios II and DE0-Nano
Introduction
Hardware
Design Flow
Quartus II Project
Top-Level Entitiy
Heartbeat
System PLL
Design Constraints File
Nios II - Qsys
Compile the design
Assign the pins
Compile the design again
Program the FPGA
Credits
Download

(2) Nut/OS
(3) N2IRvs
 

Introduction

This tutorial provides comprehensive information that will help you understand how to create a microprocessor system on your FPGA development board and run software on it. This system is based on the Altera Nios II processor. Later I will show how to use the Nut/OS on the Nios II. The tutorial is divided in the following sessions:

  1. Altera DE0-Nano
  2. Nut/OS

It is recommended to start with the Altera DE0-Nano, which is this session here. This tutorial use the Quartus II and Nios II SBT software version 11.1sp2.

I do not want to write every time "Quartus II", "Nios II" or "Altera DE0-Nano Development and Education Board" in this tutorial. Therefore I will use the short form "Quartus", "Nios" and "DE0-Nano".

Hello Altera, if you like this tutorial and want to donate something, no problem. You can find my contact data on the imprint page

Note: This tutorial here is very similar to the first one with the Altera DE1 and ChibiOS/RT. But here I will use Qsys instead of the SOPC Builder and VHDL instead of Verilog, therefore I will start by zero again.

Hardware

For this tutorial an Altera DE0-Nano board and a self-made adapter was used:

The self-made adapter is equipped with a DM9000E-H board. The DE0-Nano provides a lot of functionality. But for this tutorial only the following subset was used:

  • Cyclone IV (EP4CE22F17C6)
  • Build in USB Blaster
  • 32 MByte SDRAM
  • 2 Push-button switches
  • 4 Toggle switches
  • 8 Green User LEDs
  • 50 MHz oscillator

The self-made adapter can also be used for the DE1 board. At the end of this session, you will find the final projects for the DE0-Nano and DE1 board.

Design Flow

The first step in the FPGA design flow starts with the design entry. The standard design entry methods are using schematics or a hardware description language (HDL), such as Verilog or VHDL. The design entry step is where the designer creates the digital circuit to be implemented inside the FPGA. The flow then proceeds through compilation, simulation, programming, and verification in the FPGA hardware.

This tutorial describes all of the steps except the simulation. The part of the Design is a huge part. Therefore it is divided in smaller chunks. I assume that the Quartus software and the USB-Blaster driver is already installed on your PC. If not, please take this step before.

At the end of this tutorial you will have created a FPGA design which contains a Nios processor. In the next session, (2) Nut/OS we will create a Nut/OS application which runs on the Nios cpu. Let's start with the Topfdeckel, sorry, Top-Level Entity...

Quartus II Project

First of all we must create a new Quartus project. A project is a set of files that maintain information about your FPGA design. The Quartus Settings File (.qsf) and Quartus Project File (.qpf) files are the primary files in a Quartus project.

Start the Quartus software and select "File > New Project Wizard". The window will look like:

(Click inside the picture to expand)

Click "Next"and enter the following information about your project: (Note: File names, project names, and directories in the Quartus software cannot contain spaces. In general, do not use spaces in file names or directories.).

What is the working directory for this project? Enter a directory in which you will store your Quartus project files for this design. Here I will use "c:\my_design\NiosIIandNutOS\de0_nano_fpga" What is the name of this project? Please use "de0_nano_system"

What is the name of the top-level design entity for this project? Please use "de0_nano_system" here too. The next window should look like:

(Click inside the picture to expand)

Click "Next". Now you will come to page 2 of 5 (Add File), press "Next" too. In the next window you must assign a FPGA device to your design. Change the "Device family" to "Cyclone IV E" and use "EP4CE22F17C6" for the device. The dialog should look like:

(Click inside the picture to expand)

Click "Next" twice, the summary should look like:

(Click inside the picture to expand)

Click "Finish", now you have created the "de0_nano_fpga" project. The "Project Navigator" should look like:

Next we will create the Top-Level Entity.

Top-Level Entity

Btw, what is a "Top-Level Entity"? It is the outer rim of your design which represent the interconnections to the outer world of the FPGA. Quartus supports the following options for a Top-Level Entity:

  • Block Diagram/Schematic File
  • VHDL File
  • Verilog File

Here in this tutorial I will use a VHDL File for the Top-Level Entity. Compared to a Block Diagram a HDL File is not so clearly represented, but more fexible for me. Now we will start to create the Top-Level Entity.

Therefore select "File > New... > VHDL File", the window will look like:

Press "OK" now. A new blank file (Vhdl1.v) was created by Quartus, it should look like:

(Click inside the picture to expand)

Now we will cheat a little bit, here I have prepared the file for you. Please copy the content of de0_nano_system_vhd to the new file which was created by Quartus.The Quartus editor window
should look like:

(Click inside the picture to expand)

OK, now the file must be saved. Use "File > Save", navigate to "c:\my_design\NiosIIandNutOS\de0_nano_fpga" and type "de0_nano_system.vhd" for the filename. The dialog should look like:

Press "Save" to close this dialog. Now we can go to the next step.

Heartbeat

At the end of the tutorial you will program the FPGA. But in the moment you have no real feadback if your design is working. Therefore a blinking LED will be added which start after programming the FPGA. This is now the "heartbeat" of the FPGA. The same procedure like before.

Select "File > New... > VHDL File", press "OK". A new blank file (Vhdl2.v) was created by Quartus. Here we will cheat a little bit too. Please copy the content of heartbeat_vhd to the new file, which was create by Quartus.

Now the file must be saved. Use "File > Save", navigate to "c:\my_design\NiosIIandNutOS\de0_nano_fpga" and type "heartbeat.vhd" for the filename. Press "Save" to close the dialog.

Take a look in the "Files" tab of the "Project Navigator", here you sould find two files now, de0_nano_system.vhd and heartbeat.vhd. The window will look like:

(Click inside the picture to expand)

In the next step we will create the "engine" of the design. A PLL driven by the external clock.

System PLL

The PLL will be created with a Wizard, therefore use "Tools > MegaWizard Plug-In Manager". The MegaWizard Plug-In Manager (what a long name) appears, the first window will look like:

(Click inside the picture to expand)

Click "Next". In the new page [page 2a] expand the folder "I/O" and select ALTPLL. For "Which device family will you be using" select "Cyclone IV E". Under “Which type of output file do you want to create?” select "VHDL". And for “What name do you want for the output file?” type "pll_sys.vhd". The page should now look like:

(Click inside the picture to expand)

Click "Next", and be prepared for a long story, you will see now page 3 of 14
( not "Seven of Nine" ). For device speed grade choose 6 and set the frequency of the inclock0 input to 50 MHz. The window should look like:

(Click inside the picture to expand)

Click "Next". Now you are on page 4 of 14, unselect all options first, and select "Create 'locked' output" and "Enable self-reset on loss lock". The locked output will be used to hold the Nios in reset while the PLL is not locked. The window should look like:

(Click inside the picture to expand)

Click "Next" four times. Now you are on page 8 of 14, and will setup the output clock for c0. Select "Enter output clock frequency" and set frequency to 100 Mhz. The window should look like:

(Click inside the picture to expand)

Again, click "Next". Now you are on page 9 of 14. We need c1 for the SDRAM, therefore enable the option "Use this clock" and select "Enter output clock frequency". The same like before. Set the frequency to 100 MHz. And set the "Clock phase shift" to -54 deg.


Why -54 deg? Please take a look in the "Using the SDRAM on Altera's DE0-Nano Board with VHDL Designs" which can be find here. This PDF will explain why you need a phase shift in chapter 7. But in the document 3ns is used for a clock of 50MHz. 3ns at 50MHz is equivalent to 54 deg. Help, if anyone comes to an other result, please send me a note. Btw, here we are using 100MHz instead of 50MHz. Therefore I decide to change from ns to deg.


The window look like:

(Click inside the picture to expand)

Please click "Next" now. You will come to page 10 of 14. Here we will use c2 too, it will be used for the heartbeat. Enable the option "Use this clock" and select "Enter output clock frequency". Set the frequency to 10 MHz. The window should now look like:

(Click inside the picture to expand)

And now, press "Finish" twice. The MegaWizard Plug-In Manager will be closed. And the following dialog is shown:

Press "Yes" to add the Quartus IP to your design. A pll_sys IP block was created and added to your project. The "Files" folder from the "Project Navigator" should look like:

Timing constraints, what is this? We will create this file in the next section.

Design Constraints File

Select "File > New... > Synopsys Design Constraints File", press "OK". A new blank file (SDC1.sdc) was created by Quartus. Again, we will cheat here too. Please copy the content of de0_nano_system_sdc to the new file, which was create by Quartus.

Now the file must be saved. Use "File > Save", navigate to "c:\my_design\NiosIIandNutOS\de0_nano_fpga" and type "de0_nano_system.sdc" for the filename. Press "Save" to close the dialog. The "Files" folder from the "Project Navigator" should look like:


Why we need a SDC File? To give the TimeQuest Timing Analyzer the possibility to check if the timing of the design will fit in the FPGA, some "parameters" for the calculation are needed. This "parameters" are stored in the SDC file. For example you will find the following line in the file:

create_clock -period 50MHz [get_ports CLOCK_50]

This line tells the Analyzer that there exist a port with the name "CLOCK_50". It will be used as a clock signal with 50 MHz.

Even there will not only timing parameters saved in this file. For more information please take a look in the documentation. Help, if someone can explain it better, please send me a note.


In the next section the "CPU" will be designed.

Nios II - Qsys

We will not really create the CPU here itself. We will create the system with CPU and peripherals.

Start Qsys by using "Tools > Qsys", the new windows will look like:

(Click inside the picture to expand)

Select the clk_0 component and right-click, then select "Rename":

Change the name from "clk_0" to "clk_sys" and press return.

Double click the "clk_sys" name and change the "Clock frequency" from 50MHz to 100MHz, and "Reset synchronous edges" to "Deassert":

Press "Finish" to close the dialog.

Now we will add a Nios II processor. In the left hand-side Component Library tree, select "Library > Embedded Processors > Nios II Processor", it should look like:

Press the "Add…" button to open the Nios II component wizard. The wizard will look like:

(Click inside the picture to expand)

The "Nios II/f" core is selected, but we want to add a little more speed to the CPU, therefore select the "Caches and Memory Interfaces" tab. Change the "Instruction Cache" to "8 Kbytes" and the "Data Chache" to "4 Kbytes". The window should look like:

(Click inside the picture to expand)

Click "Finish" to return to the main window, it should look like:

(Click inside the picture to expand)

Select the "nios2_qsys_0" component and right-click, then select "Rename":

Rename the "nios2_qsys_0" to "cpu", it should now look like:

(Click inside the picture to expand)

Don't worry about the Error messages. The errors will be resolved during the tutorial.

The next step will be to add the System ID. Therefore select "Library > Peripherals > Debug and Performance > System ID Peripheral" and click the "Add..." button. We will use the default values of the wizard, press "Finish". Important, rename "sysid_0" to "sysid". The main window should now look like:

(Click inside the picture to expand)

The next component is the SDRAM, select "Library > Memories and Memory Controllers > External Memory Interfaces > SDRAM Interfaces > SDRAM Controller" and clicking the "Add…" button. The SDRAM wizard will be opened. Change the "Presets" to "Custom", "Data width Bits" to "16", "Row" to "13" and "Column" to "9". The window of the wizard should look like:

(Click inside the picture to expand)

Press "Next >", here change:

  • "Initialization refresh cycles" to 8
  • "Issue one refresh command every" to 7.8125
  • "Delay after powerup, before initialization" to 200

The window should look like:

(Click inside the picture to expand)

Click "Finish" to return to the main window. Important, rename the "sdram_0" to "sdram", the system should look like:

(Click inside the picture to expand)

Now the system contains a CPU, the Sys ID and an external SDRAM. The next step will be to add the EPCS Controller. Therefore select "Library > Memories and Memory Controllers > External Memory Interfaces > Flash Interfaces > EPCS Serial Flash Controller" and click the "Add..." button. We will use the default values of the wizard, press "Finish". Important, rename "epcs_flash_controller_0" to "epcs_flash_controller". The main window should now look like:

(Click inside the picture to expand)


Perhaps you are asking, "why every time is it important to rename the components"?

At the beginning we have cheated a little bit. The VHDL source contains references to the name of the components. Therefore it is important that we now rename the components. Even the source of the application contains some references.


For the Nut/OS we need a timer too. Use "Library > Peripherals > Microcontroller Peripherals > Interval Timer" and click the "Add…" button. Set the "Period" to 1 ms. The wizard will look like:

(Click inside the picture to expand)

If the settings are equal like in the the picture, press "Finish" otherwise you must change it. Important, rename "timer_0" to "sys_clk_timer". The main window will now look like:

(Click inside the picture to expand)

The next component is a UART. Therefore select "Library > Interface Protocols > Serial > UART (RS-232 Serial Port) " and click the "Add…" button. The wizard will look like:

(Click inside the picture to expand)

Check if the settings are equal, press "Finish" otherwise you must change it. Important, do not rename the uart_0. The main window will now look like:

(Click inside the picture to expand)

Now we need some GPIO' to control the LEDs and reading the switches. Add the "Library > Peripherals > Microcontroller Peripherals >PIO (Parallel I/O)" component to the system. For the green LEDs we need a output port with a width of 7 bit. Set the "Width" to "7", the "Direction" to "Output" and enable "Enable individual bit setting/clearing". The window of the wizard will look like:

(Click inside the picture to expand)

Click "Finish" to close the wizard. Important, rename "pio_0" to "pio_led_green". The main window will now look like:

(Click inside the picture to expand)

We need two more ports, but now we need input ports for the switches and keys. Add the "Library > Peripherals > Microcontroller Peripherals > PIO (Parallel I/O)" component to the system. For the keys we need an input port with a width of 2 bit. Set the "Width" to "2" and the "Direction" to "Input". The window of the wizard will look like:

(Click inside the picture to expand)

Press "Finish". Important, rename "pio_0" to "pio_key". The main window will now look like:

(Click inside the picture to expand)

We need a port again. Add an input port for the switches, here we need 4 bits. Important, rename "pio_0" to "pio_sw". The main window will now look like:

(Click inside the picture to expand)

The next component is the Ethernet DM9000E Interface. Unfortunately this component is not available in the library. Here you can use one of my components. First of all, create a new folder in you project and rename it to "ip". Your project folder should now look like:

Here the new folder named "ip" was created. Download the DM9000E Interface ZIP, and place the file inside the "ip" folder. Now extract the ZIp file. This should create a new folder called "dm9000e" inside your "ip" folder. The content of the "ip" folder should look like:

Delete the ZIP file now. You have now installed a new component for Qsys. To make it available to Qsys too, press "F5" inside Qsys to refresh the system. After that there should be no error in the message window:

Click "Close", the new "Ethernet DM9000E Interface" should now be available in the Component Library:

The same procedure as before to add a component. Select "Project > Ethernet DM9000E Interface" and click the "Add…" button. The wizard will look like:

(Click inside the picture to expand)

Click "Finish" to close the wizard. Important, rename "dm9000e_0" to "dm9000e". The main window will now look like:

(Click inside the picture to expand)

We are now on the home stretch and must only add 3 components. The next is the SPI bus. Use "Library > Interface Protocols > Serial > SPI (3 wire Serial)" and click the "Add…" button. Change the "SPI clock (SCLK) rate" to "1536000". The wizard will look like:

(Click inside the picture to expand)

If the settings are equal like in the picture, press "Finish" otherwise you must change it. Important, do not rename "spi_0". The main window will now look like:

(Click inside the picture to expand)

For controlling the vscodec we need some GPIO's too. Add the "Library > Peripherals > Microcontroller Peripherals > PIO (Parallel I/O)" component to the system. We need a output port with a width of 3 bit. Set the "Width" to "3", the "Direction" to "Output" and enable "Enable individual bit setting/clearing".

Click "Finish" to close the wizard. Important, rename "pio_0" to "pio_vscodec". The main window will now look like:

(Click inside the picture to expand)

At the end a GPIO with interrupt functionality is needed. Add the "Library > Peripherals > Microcontroller Peripherals > PIO (Parallel I/O)" component to the system. We we need an input port with a width of 1 bit. Set the "Width" to "1", the "Direction" to "Input", enable "Synchronously capture", set the "Edge Type" to "RISING", enable "Enable bit-clearing for edge capture register", enable "Generate IRQ" and set the "IRQ Type" to "EDGE". The window of the wizard will look like:

(Click inside the picture to expand)

Click "Finish" to close the wizard. Important, rename "pio_0" to "pio_int3". The main window will now look like:

(Click inside the picture to expand)

Now we will start to solve the errors. First we will create a global reset network. Select "System > Create Global Reset Network":

This should solve some of the errors, and will connect the Reset to each component. The main window will now look like:

(Click inside the picture to expand)

Next the clock network must be connected. Unfortunately this must be done by yourself. If you move the mouse over the connection point of the "clk" from the "clk_sys" component, Qsys will display possible connections:

Connect the clock to all components. The main window will now look like:

(Click inside the picture to expand)

Next the data and instruction bus must be connected to the components. If you move the mouse over the "control_slave" signal of the "sysid", Qsys will display possible connections:

Please connect the "cpu.data_master" bus to all components. Double check that you using the "data_master". The main window will now look like:

(Click inside the picture to expand)

Now all components are connected with the "cpu.data_master". But the SDRAM must be connected with the "cpu.instruction_master" too. Without this connection, no program can be executed out of the SDRAM. The SDRAM connection should now look like:

In the moment we have 29 Errors. The next step is to assign a base address to each component. Select "System > Assign Base Addresses":

This will reduce the error count to 4 only. No we will solve the errors with the "Reset vector" and "Exception vector" of the CPU. Right click on the cpu component and select "Edit…" from the list. The wizard page of the cpu will be opened. Change the "Reset vector memory" and "Exception vector memory" to "sdram.s1". The window of the wizard should now look like:

(Click inside the picture to expand)

Click "Finish". The Errors are now gone, but we have 16 Warnings. The main window will look like:

(Click inside the picture to expand)

Let's start to solve the warnings. The warning looks like "aaa must be exported, or connected to a matching conduit." This mean that there exist some "wires" which must be connected to the "outside" of the cpu. We will start with the SDRAM. Click in the row of the "wire" from the SDRAM at "Click to export". The main window will look like:

Important, rename the "sdram_wire" to "sdram". It should now looks like:

Parts from the following components must be exported and renamed:

  • epcs_flash_controller => epcs
  • uart_0 => uart_0
  • pio_led_green => pio_led_green
  • pio_key => pio_key
  • pio_sw => pio_sw
  • dm9000e => dm9000e
  • pio_dm9000e_reset => pio_dm9000e_reset
  • spi_0 => spi_0
  • pio_vscodec => pio_vscodec
  • pio_int3 => pio_int3

This will reduce the warning count to 6. The next warnings look like "Interrupt sender aaa is not connected to an interrupt receiver", this must be solved too. Scroll a little bit to right, and you will see the "IRQ" column. We will start with the epcs flash controller, if you move the mouse to the "IRQ" column, Qsys will display possible connections. Double click on the connection point and use 8 for the IRQ.

The following components need a interrupt assignment too:

  • sys_clk_timer => 0
  • uart_0 => 4
  • dm9000e => 1
  • spi_0 => 2
  • pio_int3 => 3
  • epcs_flash_controller => 8

This will solve all warnings, and we have still 5 Info messages. Some of the info messages looks like "PIO inputs are not hardwired in test bench. Undefined values will be read from PIO inputs during simulation." To solve this, edit all input GPIO's and set the option "Hardwire" PIO inputs in test bench".

Only 2 Info messages should be available now:

  • System ID will no longer be automatically assigned.
  • Time stamp will be automatically updated when this component is generated.

These infos can be ignored.

We can now create our system, therefore change to the "Generation" tab.

Click the "Generate" button, a window will pop up which will look like:

Click "Save", and use "system" for the filename. The dialog should look like:

Press "Save" to close this dialog. Now Qsys will generate the system. This can take a moment:

At the end you should see the Info: "Generate Complete. 0 Errors, 8 Warnings" The warnings are internal warnings, and we can ignore these special warnings here. Click "Close" to close the dialog.

Use "File > Exit" to close Qsys and return to the Quartus window. Right click on the "Files folder" in the Project Navigator:


Click "Add/Remove Files in Project...". A "Settings" dialog will be opened which will look like:

(Click inside the picture to expand)

We will now add the "system" which was created by the Qsys. Therefore press the "..." button on the left side of the "Add" button:


The "Select File" dialog will pop up. Change the "Type" to "IP Variation Files (*.qip)" and go into the "system" folder. Here you will find a new folder "synthesis", go into. Here select "system.qip" and press "Open". Now you can use the "Add" button to add the file to the project:


Press "Add". The file "system/synthesis/system.qip" will now be listed by the other files too. Click "OK" to close the dialog. You will now find the "system/synthesis/system.qip" in the "Project Navigator" too. The "Files" folder from the "Project Navigator" should look like:

In the next section we will compile the design.

Compile the design

Compile the project, by selecting "Processing > Start Compilation":


This will start the compilation process which can take a while:

(Click inside the picture to expand)

At the end of the compilation process a dialog box should appear which give you the information about a successful completion:

Here we have 76 warnings and 1 "Critical Warning":

No exact pin location assignment(s) for 89 pins of 89 total pins.

Therefore in next section we will assign the pins of the FPGA.

Assign the pins

Now we can assign the input and output pins of the FPGA. But first of all we want to set all unused pins to input tri-stated. Therefore use "Assignments > Device...". The device window will be opened:

(Click inside the picture to expand)

Click "Device and Pin Options...". A new window will pop up. Change here the "Unused Pins:" option to "As input tri-stated with weak pull-up". The window should look like:

(Click inside the picture to expand)

Click "OK" twice to close both windows. Now I will show you how to assign the pin for CLOCK_50. To open the "Pin Planer", use "Assignments > Pin Planner". A new window will be opened, it will look like:

(Click inside the picture to expand)

Double-click in the "Location" column for the CLOCK_50 signal to open a drop-down list. Select here "PIN_R8", you will got the pin information from the data sheet of the DE0-Nano board. Now double-click in the "I/O Standard" column and select "3.3-V LVTTL".

The window should now look like:

(Click inside the picture to expand)

You must repeat this procedure for all pins of your design. Do you want to cheat here? Yes, are you sure? OK, close the "Pin Planer" first. Use "File > Open...", now change the "File type" to "All Files (*.*)" and select the "de0_nano_system.qsf" file. Open this file.

This is the file where the pin assigment is stored too. Copy the content of this file at the end of the qsf file. After this, close the qsf file, click "Yes" if Quartus want to save.

Hopefully Quartus has accept the input? We will check this and open the "Pin Planer" again. Use "Assignments > Pin Planner" and scroll through the "All Pins" list. It looks that the cheat was working on my side :o)

(Click inside the picture to expand)

We must compile the design again, this will be done in the next section.

Compile the design again

Like in the section before. Compile the project, by selecting "Processing > Start Compilation":


This will start the compilation process which can take a while. "Please hold the line..."

At the end of the compilation process a dialog box should appear which give you the information about a successful completion:

There should be no, I will repeat it, no "Critical Warning" available. The SOF file was created and we can program the FPGA in the next section.

Program the FPGA

I assumed that you have connect the DE0-Nano board still with your computer and the USB-Blaster driver is still installed. For programming the FPGA select "Tools > Programmer". Because of the absent Nios  license I got a message about the OpenCore Plus feature:

Press "OK", and the programmer window will be opened:

(Click inside the picture to expand)

Everythink looks ok here. Click the "Start" button to program the FPGA. If you have problems to program the FPGA, press the "Start" button again. If the LED7 is blinking and the "Progress" indicator looks like:

Drum roll, congratulations, you have created, compiled, and programmed your design! The compiled SRAM Object File (.sof) is loaded onto the FPGA on the development board and the design should be running.

In the next session I will show you how to use Nut/OS on the DE0-Nano board.

Credits

  • Thanks go to Terasic which give me the permision to use parts of the DE0-Nano
    user manual for this tutorial.
  • And many thanks goes to the "spell checker" too, if I have found someone.

Download

Quartus de0_nano_fpga VHDL project (100MHz), for the Altera DE0-Nano board (42 KB)

Quartus de0_nano_fpga VHDL project (140MHz), for the Altera DE0-Nano board (42 KB)

Quartus de1_fpga VHDL project (100MHz), for the Altera DE1 board (52 KB)