Monday 26 May 2014

Using a PLL to correct the SDRAM clock when using a Nios II on the DE0-Nano

In my previous blog post Connecting the SDRAM to a Nios II on the DE0-Nano I wrote about my experiences of connecting up the 32MByte SDRAM chip to the Nios processor. Hooray it all worked as expected. 

But is there an issue in the design that is waiting to cause me trouble! The clock skew depends on the physical characteristics of the DE0-Nano board [2]. The sdram_clock needs to lead the system clock in the design by 3 nanosecond. This can be done using a PLL or Phased-Locked-Loop.

Phased-Locked-Loop

A Phase-Locked-Loop or PLL is a control system that will produce an output signal that is related to the phase of the input signal. They can be used to increase or decrease the clock frequency. They can more importantly in our case allow us to produce another clock that has the same frequency as the source but is out of phase by a fixed amount. The Cyclone IV E used on the DE0-Nano has a general purpose PLL that can be used of extending memory interfaces and is ideal for what we want to do. 

Adding a PLL

The MegaWizard plugin manager can be used to generate and configure our PLL.


When the megawizrd start we need to first select the correct PLL component called ALTPLL and give it a name. I have called mine sdram_pll.


The input frequency feeding the PLL is 50Mhz.


I removed the signal telling me when the PLL what frequency and phase lock. I am not worried about that in this design.


Finally I configure the output frequency of the PLL to be the same as the input frequency but with a  phase shift of -3ns. That's all I need to generate and configure my PLL. All I need to do now is stitch the PLL into my design.

VHDL

To the architecture in my previous post I added the following component deceleration for the PLL:

component sdram_pll is
PORT
(
 areset : IN STD_LOGIC  := '0';
 inclk0 : IN STD_LOGIC  := '0';
 c0 : OUT STD_LOGIC 
);
   end component;

I also needed to add a signal for the rest because the PLL reset is active high and the Nios II reset is active low!

  signal reset: std_logic;

Not we have the component we can connect it into our VHDL architecture.

--pin_sdram_clk <= pin_clk;

reset <= not pin_reset_n;
 
sdram_pll_inst : sdram_pll port map 
  (
  areset  => reset,
  inclk0  => pin_clk,
  c0      => pin_sdram_clk
  );

You can see I have just comment out the existing line that connects the sdram_clk with the system clock and replaced with the PLL component. Notice written the logic to invert the the reset input because the reset is active high. I have taken the reset directly from the reset pin. This is something I do not like doing an in my next post I will address this issue. However for now it is done and it works.  



The final design with the PLL in place is now finished. 

References




Thursday 22 May 2014

Connecting the SDRAM to a Nios II on the DE0-Nano

I my last post Simple Nios II on the DE0-Nano I create a Nios II Processor from scratch. The Nios II design used 20K Bytes of On-Chip memory to store and execute its program. Having 20K of RAM is only enough for the most simple of applications. Lucky the DE0-Nano has 32Mbytes of SDRAM. This is plenty of RAM to do lots of complex algorithms. This post looks at how to attach the 23Mbytes of SDRAM to a Nios II running on the DE0-Nano demo board.

What is SDRAM

Synchronous Dynamic Random Access Memory or SDRAM is memory that is synchronized to the system clock. The memory is divided into a number of different banks allowing the memory to use a number of them at the same time. This can result in higher data rates than it non-synchronous equivalent DRAM.

Qsys

Building on the design produced in xx we need to add the SDRAM controller block to our Qsys design for the Nios II system.


Once the component is added we need to connect it to the Nios processor. Make sure that both the data and instruction buses are connected. 


One the SDRAM controller is connected we need to chance the reset and exception addresses from their location within on-chip ram to their new location within the SDRAM.  


Once the Nios II reset and exceptions are changed we can generate our Qsys model and close Qsys. We now need to modify our VHDL to connect in the SDRAM.

VHDL


The VHDL was updated with a new Qsys component that included the extra signals needed to access the SDRAM:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity de0nano1 is
   port
    (
     pin_clk         : in    std_logic;
     pin_reset_n     : in    std_logic;
     pin_led_pio     : out   std_logic_vector(7 downto 0);
     pin_sdram_addr  : out   std_logic_vector(12 downto 0);            pin_sdram_ba    : out   std_logic_vector(1 downto 0);            pin_sdram_cas_n : out   std_logic;                                pin_sdram_cke   : out   std_logic;                                pin_sdram_cs_n  : out   std_logic;                                pin_sdram_dq    : inout std_logic_vector(15 downto 0) := (others => 'X'); 
     pin_sdram_dqm   : out   std_logic_vector(1 downto 0);            pin_sdram_ras_n : out   std_logic;                                pin_sdram_we_n  : out   std_logic;
     pin_sdram_clk   : out   std_logic
     );
end entity;

architecture arch_de0nano1 of de0nano1 is

  component my_nios1 is
    port 
    (
     clk_clk              : in  std_logic := 'X'; 
     reset_reset_n        : in  std_logic := 'X'; 
     led_pio_external_connection_export : out std_logic_vector(7 downto 0);
     sdram_addr           : out   std_logic_vector(12 downto 0); 
     sdram_ba             : out   std_logic_vector(1 downto 0);  
     sdram_cas_n          : out   std_logic;                     
     sdram_cke            : out   std_logic;                     
     sdram_cs_n           : out   std_logic;                     
     sdram_dq             : inout std_logic_vector(15 downto 0) := (others => 'X'); 
     sdram_dqm            : out   std_logic_vector(1 downto 0);  
     sdram_ras_n          : out   std_logic;                     
     sdram_we_n           : out   std_logic                      
      );
  end component my_nios1;
  
begin

  inst_nios: component my_nios1 port map 
    (
      clk_clk                            => pin_clk, 
      reset_reset_n                      => pin_reset_n, 
      led_pio_external_connection_export => pin_led_pio,
      sdram_addr                         => pin_sdram_addr, 
      sdram_ba                           => pin_sdram_ba, 
      sdram_cas_n                        => pin_sdram_cas_n ,  
      sdram_cke                          => pin_sdram_cke,  
      sdram_cs_n                         => pin_sdram_cs_n,  
      sdram_dq                           => pin_sdram_dq, 
      sdram_dqm                          => pin_sdram_dqm ,  
      sdram_ras_n                        => pin_sdram_ras_n,   
      sdram_we_n                         => pin_sdram_we_n  
    );
 
    pin_sdram_clk <= pin_clk;
 
end architecture arch_de0nano1;

When complied this VHDL will create the following RTL. It is interesting to note that the SDRAM clock is being driven directly by the system clock. However even though this design works it would be better to drive the clock line from a PLL. I will discuss this in a future post.


Before we compile our final design we must assign the correct pin to make the physical connection on our DE0-Nano device. I have include the TCL below to illiterate the connections made:

set_location_assignment PIN_A15 -to pin_led_pio[0]
set_location_assignment PIN_A13 -to pin_led_pio[1]
set_location_assignment PIN_B13 -to pin_led_pio[2]
set_location_assignment PIN_A11 -to pin_led_pio[3]
set_location_assignment PIN_D1 -to pin_led_pio[4]
set_location_assignment PIN_F3 -to pin_led_pio[5]
set_location_assignment PIN_B1 -to pin_led_pio[6]
set_location_assignment PIN_L3 -to pin_led_pio[7]

set_location_assignment PIN_E1 -to pin_reset_n
set_location_assignment PIN_R8 -to pin_clk

set_location_assignment PIN_L4 -to pin_sdram_addr[12]
set_location_assignment PIN_N1 -to pin_sdram_addr[11]
set_location_assignment PIN_N2 -to pin_sdram_addr[10]
set_location_assignment PIN_P1 -to pin_sdram_addr[9]
set_location_assignment PIN_R1 -to pin_sdram_addr[8]
set_location_assignment PIN_T6 -to pin_sdram_addr[7]
set_location_assignment PIN_N8 -to pin_sdram_addr[6]
set_location_assignment PIN_T7 -to pin_sdram_addr[5]
set_location_assignment PIN_P8 -to pin_sdram_addr[4]
set_location_assignment PIN_M8 -to pin_sdram_addr[3]
set_location_assignment PIN_N6 -to pin_sdram_addr[2]
set_location_assignment PIN_N5 -to pin_sdram_addr[1]
set_location_assignment PIN_P2 -to pin_sdram_addr[0]

set_location_assignment PIN_K1 -to pin_sdram_dq[15]
set_location_assignment PIN_N3 -to pin_sdram_dq[14]
set_location_assignment PIN_P3 -to pin_sdram_dq[13]
set_location_assignment PIN_R5 -to pin_sdram_dq[12]
set_location_assignment PIN_R3 -to pin_sdram_dq[11]
set_location_assignment PIN_T3 -to pin_sdram_dq[10]
set_location_assignment PIN_T2 -to pin_sdram_dq[9]
set_location_assignment PIN_T4 -to pin_sdram_dq[8]
set_location_assignment PIN_R7 -to pin_sdram_dq[7]
set_location_assignment PIN_J1 -to pin_sdram_dq[6]
set_location_assignment PIN_J2 -to pin_sdram_dq[5]
set_location_assignment PIN_K2 -to pin_sdram_dq[4]
set_location_assignment PIN_K5 -to pin_sdram_dq[3]
set_location_assignment PIN_L8 -to pin_sdram_dq[2]
set_location_assignment PIN_G1 -to pin_sdram_dq[1]
set_location_assignment PIN_G2 -to pin_sdram_dq[0]
set_location_assignment PIN_T5 -to pin_sdram_dqm[1]
set_location_assignment PIN_R6 -to pin_sdram_dqm[0]

set_location_assignment PIN_M6 -to pin_sdram_ba[1]
set_location_assignment PIN_M7 -to pin_sdram_ba[0]

set_location_assignment PIN_L1 -to pin_sdram_cas_n
set_location_assignment PIN_L7 -to pin_sdram_cke
set_location_assignment PIN_R4 -to pin_sdram_clk
set_location_assignment PIN_P6 -to pin_sdram_cs_n
set_location_assignment PIN_L2 -to pin_sdram_ras_n
set_location_assignment PIN_C2 -to pin_sdram_we_n

Eclipse

The last thing to do before we can make use of our connected SDRAM is change some of the compiler setting in Eclipse to pint to the external of memory.  






Finally we can now true off the reduced device driver and small c library. We can also have enough memory to support the C++ library if needed.  



That it we have now added external SDRAM to our Nios II running on the DE0-Nano. Do not forget it is better to use a PLL to drive the clock. I will chat about this in my next post.

References




Saturday 17 May 2014

Simple Nios II on the DE0-Nano - Part 4 of 4 (Nios Software)

In my last post I created the VHDL need to instantiate the VHDL component of my Niso processor. In this post  am going to do the final step and write some very simple software to flash the LED's

Download to the device


Make sure you VHDL hardware is downloaded into the FPGA before we start.

Create an new project



 Using the template I first create a new project called my_nios. I have selected the Hello World template as my starting ping for the code.


Because we only have 20k Bytes of RAM in our design we need to make out code memory footprint as small as possible. We do this by changing the properties on the BSP (Board support package) to remove C++ support and enable reduced device drives and small C library.

You should now be able to compile you simple Hello World program to ensure there are no errors be for we modify it with some LED flashing code!

Software

The following C-program is what I have written to flash my LEDs. To keep it simple as possible I did not even use any timers for create a delay instead I chose to use a simple FOR loop. No the best delay I know but it works for this program!  

#include <stdio.h>
#include <system.h>
#include <altera_avalon_pio_regs.h>

void simple_loop_delay()
{
   int l;
   for (l=0; l<100000;l++);

}

int main()
{
  printf("Hello from Nios II!\n");

  while(1)
  {
     IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0xaa);
     simple_loop_delay();

     IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0x55);
     simple_loop_delay();
  }

  return 0;
}

The BSP (Board Support Package) generates a file for each peripheral you have in the system and a system.h file.

It the program above the system.h holds the address of the PIO block LED_PIO_BASE. It is best to use this instead of an absolute address because if the hardware changes then the address could also change.

The altera_avalon_pio_regs.h holds the prototypes to access the PIO peripheral. We are using the  IOWR_ALTERA_AVALON_PIO_DATA command. Writing 0xaa then 0x55 will flash the LEDs backwards and forwards.

That it! In this series of blog posts we have created and empty project, built a Qsys system, build the Qsys component  into VHDL and finally written some software. And yes it was all very straight forward.

---

Simple Nios II on the DE0-Nano - Part 3 of 4 (VHDL)

In my last port we connected the blocks together to for our Nios System using Qsys that will flash the LEDs on the DE0-Nano development board. This block now needs to be stitched into our FPGA design and VHDL is my weapon of choice.

VHDL




Using the VHDL component templeate from Qsys we can create a simple piece of VHDL to instantiate the component and take the route the IO out to the pins of the device.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity de0nano1 is
  port
  (
   pin_clk    : in  std_logic;
   pin_reset_n: in  std_logic;
   pin_led_pio: out std_logic_vector(7 downto 0)
   );
end entity;

architecture arch_de0nano1 of de0nano1 is

  component my_nios1 is
    port 
    (
    clk_clk                            : in  std_logic := 'X'; 
    reset_reset_n                      : in  std_logic := 'X'; 
    led_pio_external_connection_export : out std_logic_vector
                                                 (7 downto 0) 
      );
  end component my_nios1;
  
begin

  inst_nios: component my_nios1 port map 
    (
      clk_clk                            => pin_clk, 
      reset_reset_n                      => pin_reset_n, 
      led_pio_external_connection_export => pin_led_pio 
    );
 
end architecture arch_de0nano1;

The only other thing we need to do before we place and route the design is assign the pins for the clock, reset and the leds in the DE0-Nano. The following is some TCL that will make the process easy for you.

set_location_assignment PIN_E1 -to pin_reset_n
set_location_assignment PIN_R8 -to pin_clk
set_location_assignment PIN_A15 -to pin_led_pio[0]
set_location_assignment PIN_A13 -to pin_led_pio[1]
set_location_assignment PIN_B13 -to pin_led_pio[2]
set_location_assignment PIN_A11 -to pin_led_pio[3]
set_location_assignment PIN_D1 -to pin_led_pio[4]
set_location_assignment PIN_F3 -to pin_led_pio[5]
set_location_assignment PIN_B1 -to pin_led_pio[6]
set_location_assignment PIN_L3 -to pin_led_pio[7]

Our soft processor is now ready for some software and that what I am going to do in my next port. 




Simple Nios II on the DE0-Nano - Part 2 of 4 (Qsys)

It first post in this series I designed on the architecture for a simple Nios II system. I also did some preliminary steps to create a project we and use as a platform to for our system.

QSYS



Qsys is the tool for designing our processor hardware. It allow the different blocks of the system to be connected together and configured. The following steps will take you through the steps in creating our system.


The first component I added was the RAM configured to be 20Kbytes. No a huge amount of memory but more than enough to write a simple program to flash some LED's. 


Next I added the processor. I used the economic version of the Nios because this will work with the web edition of the software without any additional licenses. Note you can only set the reset and exception vectors once it has been connected to the RAM.


The JTAG uart  will allow us to download our software from the PC into the RAM.


The System ID is used to match the hardware and the software. You should never build any Nios system without a System ID component include. 


The PIO is configured for output only and will be used for driving the Led's.


Now all the components are included in the design we need to make sure all the blocks are connect correctly.


Once we have finished building the system you can look in the HDL tab and get the details of how to include a component. We will use this in the next posts when we include our QSYS component into our FPGA design.


We have now come to the end of our QSYS section. The only thing left to do is generate our QSYS system. I have called mine my_nios1. 


In my next post we will see how we take this QSYS model and include into some hardware using VHDL!

---

Simple Nios II on the DE0-Nano - Part 1 of 4 (Project creation)

The DE0-Nano is a small development board based on the Cyclone IV FPGA from Altera. The manufactures of the board claim that it is ideal for use with the soft processor Nios II. In this series of posts I am going to explore how to build one these Nios II's. 


The Architecture


The first thing we need is the Nios II processor. However to be able to run a simple program we need some RAM to store the program in. we also need a method of getting the code out of the PC down into the memory. That's what the Jtag Uart is for. The system ID is will be used to ensure to check that we are developing software for the correct build of the FPGA. If we didn't have a system ID it could get very messy and difficult to get any software running. To create some output I have decided to do nothing more that flash some LED's. To do that I need to include a PIO in output mode only.

This system is built using Qsys. However we need to create a project in Quartus II  before we begin.


First look at Quartus II

I am using Quartus II 12.1 web edition. The following steps will set-up our project. 

The first thing we need to do is create a new project. 

Choose a suitable location and call the project de0nano1

The DE0-Nano uses a Cyclone IV E device part number EP4CE22F17C6 

You can now click Finish we are done with the project Wizard.

In my next post I will describe how to add a Qsys system to this project that implements the architecture we discussed at the start of this post.

---