More information about this project can be found at: http://www.pyroelectro.com/tutorials/de0_vhdl_vga/
GeoByJmh - Embedded Engineer
Hi I am an Embedded Engineer. I am currently researching around the subject of FPGA's. Therefore most of this blog will contain post on Altera FPGA's, VHDL and the Nios II processor. Join me on my journey and see what I find out.
Sunday, 15 June 2014
DE0-Nano FPGA VGA
I came across this video that shows the DE0-Nano being used to implement a 800 x 600 VGA display driver. I think this is cool!
Executing code on the Nios II directly after it has configured from the EPCS
I wanted my Nios II to start executing code directly after it has configured from the EPCS. The code I wanted to execute was using the On-Chip RAM. The solution was simple, however it took me longer that it should have to figure out how to do it. The following is taken from the Nios II Software Developers Handbook (p2-33) and show you how!
After your FPGA has been complied you can write it into the EPCS as normal. See Getting your design to load from the EPCS16 on the DE0-Nano development board and Scripting the process of programming the EPCS on the DE0-Nano
Creating Memory Initialization Files
After your FPGA has been complied you can write it into the EPCS as normal. See Getting your design to load from the EPCS16 on the DE0-Nano development board and Scripting the process of programming the EPCS on the DE0-Nano
References
Nios II Software Developer’s HandbookSunday, 8 June 2014
Scripting the process of programming the EPCS on the DE0-Nano
In may post Getting your design to load from the EPCS16 on the DE0-Nano development board I walked through the steps to get my FPGA stored in the EPCS16 flash device. Once you have been through the process a few time it is simple enough to be lodged in your memory. It will also become a little tiresome. This post looks at how the process can be scripted using a simple .bat file.
A special folder
I wanted create a self contained folder will all the files needed to program the the EPCS16. This gives me the ability to give the ability to update boards to anyone who is using my board. The de0nano_pmg.bat file contains the short script as follows:
copy onehertzled_top.sof de0nano_pmg.sof
C:\altera\12.1\quartus\bin\quartus_cpf -c de0nano_pmg.cof
C:\altera\12.1\quartus\bin\quartus_pgm -c "USB-Blaster [USB-0]" de0nano_pmg.cdf
pause
The first line copies the oneherztled_top.sof file to create the file de0nano_pmg.sof. The reason I do this is to keep the rest of the script generic and expecting the same file what ever design I want to load. Therefore doing this initial copy means that if I ever wanted to program another SOF file into the EPCS I would only need to edit one line in this batchfile and the whole process would work exactly the same as before.
quartus_cpf
quartus_cpf -c de0nano_pmg.cof
The quartus_cpf application is the Altera program that we will use to convert the SOF file into the JIC file (and MAP file) that is in the correct format to program into the EPCS. Notice that the quartus_cpf contains a COF file as one of its input files.
The first step in creating the COF is to follow the section "creating the right file format" in my previous post Getting your design to load from the EPCS16 on the DE0-Nano development board. Then clicking on "Save Configuration Setup" shown in the dialog above.
Saving the configuration will create the COF file. This is in fact an XML file that we can edit to change the input file name to de0nano_pmg.sof and the output file name to de0nano_pmg.jic as shown above.
quartus_pmg
quartus_pgm -c "USB-Blaster [USB-0]" de0nano_pmg.cdf
The quartus_pmg application will take the JIC and program it to the EPCS device.
The "USB-Blaster [USB-0]" is the port that the byte blaster cable is connected to. The port you cable is connected to can be found in the Altera programmer. Also we can use the Altera programmer to generate a CDF file for use in this script.
The CDF file can be edited to specify the path and JIC file to be written into the device.
Running the script
All you need to do is click on the batchfile and program your DE0-nano!
I would love to know what you thought of this post. Please leave a comment and let me know what you think! - Thanks J
Friday, 6 June 2014
Getting your design to load from the EPCS16 on the DE0-Nano development board
Introduction
I have been playing with my DE0-nano, just switching the eight LEDs between 0xAA and 0x55 once every second. The top level of my design can be seen in the image below.
I am so happy with my design!! That I decided to program it into the EPCS16 serial flash device on the DE0-Nano to loads it automatically every time the development board is powered.
What is the EPCS16
FPGA's are built using SRAM technology, which mean that every time power is removed it will loose its configuration. The EPCS16 is a flash memory device that can hold the configuration for an FPGA (and Nios II software) and automatically load it into the FPGA at power on time. The diagram below is taken from Altera - Serial Configuration (EPCS) Devices Datasheet and show how the EPCS device is connected to the FPGA.
Creating the right file format
In order to program the EPCS device the first thing we need to do is convert the SOF file that is generated as part of the synthesis process into a POF file suitable of being written into the flash device. By clicking on File > Convert Programming Files... you will see the following dialog box:
The first thing we need to do is set the programming file type and select the configuration device followed by the name of the output file.
Select the SOF data and click on add file to select the SOF file that we want to program into the flash device.
Next we need to click on the flashloader and click on add device. Selecting the Cyclone IV E and EPC4CE22 device.
You should now have a screen that looks like the following:
Select the SOF file and click on properties. Next make sure compression is selected.
We can now generate the JIC file ready to be programmed into the EPCS!
Programming the EPCS16
Now we have generated a flash file we can programming it into the EPCS device using the Altera programmer. Add the JIC file, click start and wait.
If all goes to plan you will now have your design run just after power up!!
Wednesday, 4 June 2014
Up Down counter in VHDL
I have just posted a reply to the altera forum. The thread ask the question how would you design an up/down counter in VHDL. The follwing is my solution:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity people_count is
generic
(
COUNTER_WIDTH: integer := 8
);
port (
in_clk : in std_logic;
in_reset : in std_logic;
in_incCount : in std_logic;
in_decCount : in std_logic;
out_count : out std_logic_vector(COUNTER_WIDTH-1 downto 0)
);
end entity people_count;
architecture arch_people_count of people_count is
signal count: unsigned(COUNTER_WIDTH-1 downto 0);
signal count_up: std_logic;
signal count_down: std_logic;
begin
count_up <= '1' when in_incCount ='1' and in_decCount = '0' else '0';
count_down <= '1' when in_incCount ='0' and in_decCount = '1' else '0';
process(in_clk, in_reset)
begin
if in_reset = '1' then
count <= (others => '0');
elsif rising_edge(in_clk) then
if (count_up = '1') then
count <= count + 1;
elsif (count_down = '1') then
count <= count - 1;
end if;
end if;
end process;
out_count <= std_logic_vector(count);
end architecture arch_people_count;
happy counting :-)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity people_count is
generic
(
COUNTER_WIDTH: integer := 8
);
port (
in_clk : in std_logic;
in_reset : in std_logic;
in_incCount : in std_logic;
in_decCount : in std_logic;
out_count : out std_logic_vector(COUNTER_WIDTH-1 downto 0)
);
end entity people_count;
architecture arch_people_count of people_count is
signal count: unsigned(COUNTER_WIDTH-1 downto 0);
signal count_up: std_logic;
signal count_down: std_logic;
begin
count_up <= '1' when in_incCount ='1' and in_decCount = '0' else '0';
count_down <= '1' when in_incCount ='0' and in_decCount = '1' else '0';
process(in_clk, in_reset)
begin
if in_reset = '1' then
count <= (others => '0');
elsif rising_edge(in_clk) then
if (count_up = '1') then
count <= count + 1;
elsif (count_down = '1') then
count <= count - 1;
end if;
end if;
end process;
out_count <= std_logic_vector(count);
end architecture arch_people_count;
happy counting :-)
Tuesday, 3 June 2014
Reseting my Nios II
In this blog post I will look at the reset design in the Nios II system I am designing. I will consider the pros and cons of using synchronous and asynchronous reset. My conclusion is its best to have a bit of both and use a synchronising reset circuit.
begin
if (in_reset = '1') then
out_q <= '0';
elsif (rising_edge(in_clk)) then
out_q <= in_d;
end if;
end process;
The VHDL above will generate a d-type shown in the RTL view below. It creates a reset that is independent on the clock or asynchronous.
But there is a very big disadvantage to using asynchronous resets! You cannot guarantee that the resets for all the d-types will be released in the same clock cycle. This create the small possibility of you design not coming out of reset in the way that was predicted. This could cause an intermittent fault that is tricky to track down.
Would a synchronous reset be any better?
begin
if (rising_edge(in_clk)) then
if (in_reset = '1') then
out_q <= '0';
else
out_q <= in_d;
end if;
end if;
end process;
The VHDL above will generate a d-type shown in the RTL view below. It creates a reset that is dependent on the clock or synchronous.
begin
if (reset = '1') then
out_q <= '0';
elsif (rising_edge(in_clk)) then
out_q <= in_d;
end if;
end process;
proc_reset:process(in_clk,in_reset)
begin
if (in_reset = '1') then
rst_reg <= '1';
reset <= '1';
elsif (rising_edge(in_clk)) then
rst_reg <= '0';
reset <= rst_reg;
end if;
end process;
The the VHDL above contains two processes. The top process is a d-type that we want to reset and the bottom process is a reset synchronization circuit. It produces the following RTL.
How do I reset my FPGA?
Synchronizing Asynchronous Resets / Reset Design
Asynchronous Reset
proc_dtype:process(in_clk,in_reset)begin
if (in_reset = '1') then
out_q <= '0';
elsif (rising_edge(in_clk)) then
out_q <= in_d;
end if;
end process;
The VHDL above will generate a d-type shown in the RTL view below. It creates a reset that is independent on the clock or asynchronous.
The asynchronous reset is the simplest to implement and is probably the most common type of reset used in an FPGA design. The advantage of this kind of reset is it does not need to insert any extra logic in the data path and therefore will not inadvertently increase the logic layers between d-types in an RTL stage. This mean that asynchronous reset will not impact on the data arrival time to a register input. The other big advantage of an asynchronous reset is that the reset will take effect immediately i.e. it is not dependent on the clock.
Would a synchronous reset be any better?
Synchronous Reset
proc_dtype:process(in_clk)begin
if (rising_edge(in_clk)) then
if (in_reset = '1') then
out_q <= '0';
else
out_q <= in_d;
end if;
end if;
end process;
The VHDL above will generate a d-type shown in the RTL view below. It creates a reset that is dependent on the clock or synchronous.
This reset design is fully synchronous and is therefore predictable and we can use static timing analysis such as TimeQuest to test the timing of the circuit. This kind of reset can also be easier to use when you do circuit simulation. However there is a down side to synchronous resets. Your design will be more complex and you create the risk of adding additional gate delays to accommodate the reset signal. This will produce a negative impact on the d-types set-up slack time.
However it turns out that it is possible to use an asynchronous reset, but with a synchronous release.
A bit of both Asynchronous and Synchronous
proc_dtype:process(in_clk,reset)begin
if (reset = '1') then
out_q <= '0';
elsif (rising_edge(in_clk)) then
out_q <= in_d;
end if;
end process;
proc_reset:process(in_clk,in_reset)
begin
if (in_reset = '1') then
rst_reg <= '1';
reset <= '1';
elsif (rising_edge(in_clk)) then
rst_reg <= '0';
reset <= rst_reg;
end if;
end process;
The the VHDL above contains two processes. The top process is a d-type that we want to reset and the bottom process is a reset synchronization circuit. It produces the following RTL.
This design avoids the potential problems associated with synchronous reset and purely asynchronous reset. The reset is applied asynchronously and immediately. It also does not create the additional logic we have seen with the synchronous design. However the one big advantage is that when the reset is released, it is synchronous to the clock. This mean that all the registers will be reset in the same clock cycle. You can also use static timing analysis to prove your timings.
My Nios II reset
In my post Using a PLL to correct the SDRAM clock when using a Nios II on the DE0-Nano the Nios was connected directly to the reset pin and the pll used the reset pin via a NOT gate. Based on the above discussion this has now been replaced with a reset synchronization circuit shown below:
The VHDL for this reset circuit is as follows:
library ieee;use
ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity reset_synchronization is
port
(
in_clk : in std_logic;
in_reset_n : in std_logic;
out_reset : out std_logic;
out_reset_n : out std_logic
);
end entity;
architecture arch_reset_synchronization of reset_synchronization is
signal rst_reg: std_logic;
signal reset : std_logic;
begin
proc_reset:process(in_clk,in_reset_n)
begin
if (in_reset_n = '0') then
rst_reg <= '1';
reset <= '1';
elsif (rising_edge(in_clk)) then
rst_reg <= '0';
reset <= rst_reg;
end if;
end process;
out_reset <= reset;
out_reset_n <= not reset;
end architecture;
ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity reset_synchronization is
port
(
in_clk : in std_logic;
in_reset_n : in std_logic;
out_reset : out std_logic;
out_reset_n : out std_logic
);
end entity;
architecture arch_reset_synchronization of reset_synchronization is
signal rst_reg: std_logic;
signal reset : std_logic;
begin
proc_reset:process(in_clk,in_reset_n)
begin
if (in_reset_n = '0') then
rst_reg <= '1';
reset <= '1';
elsif (rising_edge(in_clk)) then
rst_reg <= '0';
reset <= rst_reg;
end if;
end process;
out_reset <= reset;
out_reset_n <= not reset;
end architecture;
And that it! We now has a DE0-nano design with a more robust reset!. Feel free to post comments to let me know what you think.
References
Altera - Recommended Design PracticesHow do I reset my FPGA?
Synchronizing Asynchronous Resets / Reset Design
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
Subscribe to:
Posts (Atom)