VHDL tutorial based on Xilinx Spartan 3 starter kit board
|
|
by Fabrice Derepas.
|
|
I do not know anything about hardware but it seems to be fun.
|
|
These few pages gives the opportunity for newbies (like me)
to learn some stuff about VHDL and hardware design.
This tutorial is based on the very affordable ($99)
Spartan 3 starter kit board
from Xilinx.
|
|
|
 |
The goal of this first step is to write
"FFFF" on the seven-segment LED display.
This example is simple since the only thing is to do, is
to send a constant signal to the right pins.
Here is the code explained. First of all include standard declarations (do not think too much, just copy this at the beginning of each VHDL file):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Then declare an entity named ffff
with only an output vector of 7 (6 down to 0)
elements which are either '0' or '1':
entity ffff is
Port ( LED : out std_logic_vector(6 downto 0));
end ffff;
Then describes the actions of this entity, in an architecture (named for
instance Behavioral). Its job will be to write "0001110" (which
represents the letter "F" on a LED) to the outgoing vector.
Comments starts with the -- characters and ends with
the end of line.
architecture Behavioral of ffff is
begin
LED <= "0001110"; -- writes the 'F' pattern to the led.
end Behavioral;
The value "0001110" for letter comes from an arbitrary mapping
I have chosen, shown
on the schema below: first digit is for segment a, 2nd for f,
3rd for e, 4th for d, ... and 7th for g.
This arbitrary mapping
is described in a separate file,
You just have to assign elements of the LED vector
to the right pins of the FPGA. I used the following mapping,
in a file named for instance constraints.ucf:
NET "LED<0>" LOC = "E14" ;
NET "LED<1>" LOC = "G13" ;
NET "LED<2>" LOC = "N15" ;
NET "LED<3>" LOC = "P15" ;
NET "LED<4>" LOC = "R16" ;
NET "LED<5>" LOC = "F13" ;
NET "LED<6>" LOC = "N16" ;
|
 |
The goal of this exercise is to write "AnnE" on the seven-segment LED display.
This task is similar to the previous one. Since seven-segment LED displays
are timed multiplexed, we will need "something" to tell us
to write the first character, then something which tells to write the second
and so on. This will be given by a clock.
Here is our entity:
entity vhdlmodule is
Port ( CLKIN : in std_logic;
AN3 : inout std_logic;
AN2 : inout std_logic;
AN1 : inout std_logic;
AN0 : inout std_logic;
LED : out std_logic_vector(6 downto 0));
end vhdlmodule;
First of all we have an input signal which is a clock.
Then we have the AN0, ... , AN3 signals which tell the board
which of the four digit to light up.
And then we have the LED signal as in previous example.
For the clock signal we use the 50Mhz clock provided on the board.
Unfortunately this is too quick to switch beteen digits on the led panel.
So we will be using a counter named CTR, each time the counter
reaches 2^13 we change the digit to be displayed,
an we reset the counter. This whole computation
is put in something called a "process". Since this process
will only be triggered by changes of CLKIN, process declaration
is process(CLKIN). We say that the sensitivity list
of this process is CLKIN.
architecture Behavioral of vhdlmodule is
signal CTR : STD_LOGIC_VECTOR(12 downto 0);
begin
Process (CLKIN)
begin
if CLKIN'event and CLKIN = '1' then
if (CTR="0000000000000") then
if (AN0='0') then
AN0 <= '1';
LED <= "0101011"; -- the letter n
AN1 <= '0';
elsif (AN1='0') then
AN1 <= '1';
LED <= "0101011"; -- the letter n
AN2 <= '0';
elsif (AN2='0') then
AN2 <= '1';
LED <= "0001000"; -- the letter A
AN3 <= '0';
elsif (AN3='0') then
AN3 <= '1';
LED <= "0000110"; -- the letter E
AN0 <= '0';
end if;
end if;
CTR<=CTR+"0000000000001";
if (CTR > "1000000000000") then -- counter reaches 2^13
CTR<="0000000000000";
end if;
end if; -- CLK'event and CLK = '1'
End Process;
End Behavioral;
Here is the mapping of signals on the pins of the board:
NET "AN0" LOC = "D14" ;
NET "AN1" LOC = "G14" ;
NET "AN2" LOC = "F14" ;
NET "AN3" LOC = "E13" ;
NET "CLKIN" LOC = "T9" ;
NET "LED<0>" LOC = "E14" ;
NET "LED<1>" LOC = "G13" ;
NET "LED<2>" LOC = "N15" ;
NET "LED<3>" LOC = "P15" ;
NET "LED<4>" LOC = "R16" ;
NET "LED<5>" LOC = "F13" ;
NET "LED<6>" LOC = "N16" ;
Whole vhdl file
|
 |
The goal of this exercise is to draw on a VGA screen squares
with a side of 8 pixels as represented in the above picture
(click to enlarge).
This exercise is very similar to the previous one.
We need a time input to know when to display a pixel on the VGA
screen.
We will be using the 50Mhz clock clk50_in.
We will write on the red, green and blue signal.
We will have to provide vertical and horizontal sync information.
So our entity declaration looks like:
entity clockmodule is
port(clk50_in : in std_logic;
red_out : out std_logic;
green_out : out std_logic;
blue_out : out std_logic;
hs_out : out std_logic;
vs_out : out std_logic);
end clockmodule;
For the architecture part we will need three signals:
a 25Mhz clock, because the Spartan-3 Starter Kit Board User Guide
gives VGA timing for a 25Mhz pixel frequency
an horizontal_counter to count the number of pixels
per line
a vertical_counter to count the number of lines to dislay
on the screen.
So the architecture declaration starts with:
architecture Behavioral of clockmodule is
signal clk25 : std_logic; -- the 25Mhz clock
signal horizontal_counter : std_logic_vector (9 downto 0);
signal vertical_counter : std_logic_vector (9 downto 0);
This time in the body of the architecture we will find
two processes:
one to compute the clk25 signal, using clk50_in,
one to compute all out signals from clk25.
begin
-- generate a 25Mhz clock
process (clk50_in)
begin
if clk50_in'event and clk50_in='1' then
if (clk25 = '0') then
clk25 <= '1';
else
clk25 <= '0';
end if;
end if;
end process;
process (clk25)
begin
if clk25'event and clk25 = '1' then
if (horizontal_counter >= "0010010000" ) -- 144
and (horizontal_counter < "1100010000" ) -- 784
and (vertical_counter >= "0000100111" ) -- 39
and (vertical_counter < "1000000111" ) -- 519
then
red_out <= horizontal_counter(3)
and vertical_counter(3);
green_out <= horizontal_counter(4)
and vertical_counter(4);
blue_out <= horizontal_counter(5)
and vertical_counter(5);
else
red_out <= '0';
green_out <= '0';
blue_out <= '0';
end if;
if (horizontal_counter > "0000000000" )
and (horizontal_counter < "0001100001" ) -- 96+1
then
hs_out <= '0';
else
hs_out <= '1';
end if;
if (vertical_counter > "0000000000" )
and (vertical_counter < "0000000011" ) -- 2+1
then
vs_out <= '0';
else
vs_out <= '1';
end if;
horizontal_counter <= horizontal_counter+"0000000001";
if (horizontal_counter="1100100000") then
vertical_counter <= vertical_counter+"0000000001";
horizontal_counter <= "0000000000";
end if;
if (vertical_counter="1000001001") then
vertical_counter <= "0000000000";
end if;
end if;
end process;
end Behavioral;
Whole VHDL file
|
 |
This exercice is just to test the SRAM.
The idea is to display some values read in the ram on the leds.
I read the ISSI 61LV25616AL Data sheet.
I did not managed to get the data in 10ns but in only 20ns.
I guess I missed something.
If you have the correct way to do it just tell me :)
The global clock used is the default 50 Mhz clock with a DLL.
We use a single process which has 4 states given by the value
of counter ctr:
1: send read information on the SRAM, go to state 2,
2: display read information on the led, go to state 3,
3: send write information, go to state 4,
4: erase values and go to state 1.
Vhdl
Placement
|
 |
Ok, now we would like to draw something on the screen
which is read from the SRAM memory. This enables us more freedom,
because we design separate blocks with a given role:
there will be a block named vga_ctrl in charge of displaying SRAM data
on the VGA port.
the role of another block named graphic_gen will be to write in the SRAM
the patterns we want to display.
Of course we will need a dedicated block to write to the memory,
let us name it ram_ctrl,
and clocks will be managed in a fourth block named clk_gen.
This gives the following picture:
The pattern written in the SRAM by the
graphic_gen module will be a ball bouncing
on the borders of the screen. To make it simpe the ball will be represented
by a single pixel (in the style of the pong game).
|
 |
| Back to my home page |