Les objectifs du projet :
- Manipulation des tableaux en VHDL
- Savoir comment utiliser la fonction séquentielle CASE
- Comprendre l’intérêt l’utilisation des process en VHDL
- Autres astuces de programmation
Analyse de fonctionnement :
Le circuit Process_LED permet d’effectuer le codage binaire sur 4 bits en BCD 7segments. Les entrées IN1-IN4 permettent de sélectionner un nombre entre ‘0’ et ‘9’ en BCD 7 Segments puis afficher la valeur sur les trois afficheurs 7 segments. Les LED affichent en parallèle l’état des interrupteurs de l’entrée.
La notion du Process en VHDL :
Une analogie directe est d’assimiler un signal à une équipotentielle d’un circuit électronique et comparer un process à un sous-programme d’interruption dont le signal d’interruption est un événement survenu sur l’un des signaux déclarés dans la liste de sensibilité du process. Il existe différentes façons de déclarer un process, la façon la plus proche de l’analogie avec le concept d’interruption est :
–Déclaration de process
Nom du process : process (liste de sensibilité)
Begin
— Corps du process
End process nom du process
La liste de sensibilité est constituée de un ou plusieurs signaux, elle peut être vide mais nous n’envisagerons pas ce cas dans cette introduction. Le corps du process peut contenir des affectations de signaux. Ces signaux, s’ils changent d’état, déclencheront à leur tour l’invocation des process dont ils font partie de la liste de sensibilité. Il est alors primordial d’intégrer la notion de causalité et de cycles de simulation pour comprendre le fonctionnement du mécanisme des process.
L’ordre dans lequel ont été évalués les process à chaque delta-cycle n’a pas d’importance. Une simulation VHDL repose sur le principe de concurrence entre des instructions dites concurrentes tels que les process, elles sont concurrentes car elles sont toutes évaluées à un même delta-cycle.
L’évaluation d’une instruction concurrente à un delta-cycle ne peut pas influencer l’évaluation d’une autre instruction concurrente au même delta-cycle. Leur ordre d’apparition à l’intérieur d’une description VHDL n’a donc aucune importance. Par opposition, l’ordre d’évaluation des instructions séquentielles à l’intérieur d’un process doit respecter leur ordre d’apparition, comme pour un langage classique. A un même delta-cycle, une instruction séquentielle peut modifier des objets utilisés au même delta-cycle dans la suite de la description.
Les valeurs en BCD 7 segments pour un afficheur en anode commune sont stockes dans un tableur de taille 10 [0-9].
Particularités d’un Process en VHDL :
Les différents process d’un programme vhdl s’exécutent en parallèle les uns des autres.
- Un processus peut avoir des variables locales. Le fonctionnement du processus est régi par les règles suivantes :
- Un processus est une boucle infinie , lorsqu’il arrive à la fin du code, il reprend automatiquement au début
- Un processus doit être sensible des points d’arrêt, il existe 2 types de points d’arrêts :
- Le processus est associé à une « liste de sensibilité » qui réveille le processus lors d’un changement d’un des signaux.
- Le processus a des instructions d’arrêt wait dans sa description interne.
- Les variables sont internes au processus et sont affectées immédiatement, contrairement aux signaux qui eux ne sont pas affectés directement mais en fin de processus
- Un processus est séquentiel dans le sens ou les instructions sont évaluées l’une après l’autre dans l’ordre d’écriture.
La fonction CASE en VHDL :
On utilise CASE pour permettre le choix entre plusieurs actions. Cette instruction est très utile dans les machines d’états. En fin de liste, on peut ajouter WHEN OTHERS (WHEN OTHERS => NULL) qui permet de donner une action à tous les choix qui n’ont pu être trouvés dans la liste.
CASE expression IS
WHEN choices => sequence_of_statements;
{WHEN choices => sequence_of_statements;}
END CASE;Case est une fonction séquentielle, donc il faut l’intégrer dans un Process au contraire de la fonction Select.
Programme VHDL :
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std;
ENTITY Process_LED IS
GENERIC
(
N : positive :=8
);
PORT (
clk ,IN1, IN2, IN3, IN4 : IN std_logic;
TransEN1 : OUT std_logic;
TransEN2 : OUT std_logic;
TransEN3 : OUT std_logic;
Seg_value : OUT std_logic_vector(N-1 downto 0);
LED : OUT std_logic_vector(3 downto 0):=x"0"
);
END Process_LED;
ARCHITECTURE aCmpt OF Process_LED IS
SIGNAL sel : std_logic_vector(3 downto 0);
SIGNAL Seg_temp : std_logic_vector(N-1 downto 0):=x"FF";
type T_DATA is array (0 to 9) of std_logic_vector(N-1 downto 0);
-- Anode commune : Tableau des valeurs en BCD 7 Segments
constant SEG_7 : T_DATA :=
(x"C0",
x"F9",
x"A4",
x"B0",
x"99",
x"92",
x"82",
x"F8",
x"80",
x"90");
BEGIN
PROCESS (clk,IN1, IN2, IN3, IN4)
BEGIN
IF (clk'EVENT AND clk='1') THEN
CASE sel IS
WHEN x"0" => Seg_temp<=SEG_7(0); LED <=x"0";
WHEN x"1" => Seg_temp<=SEG_7(1); LED <=x"1";
WHEN x"2" => Seg_temp<=SEG_7(2); LED <=x"2";
WHEN x"3" => Seg_temp<=SEG_7(3); LED <=x"3";
WHEN x"4" => Seg_temp<=SEG_7(4); LED <=x"4";
WHEN x"5" => Seg_temp<=SEG_7(5); LED <=x"5";
WHEN x"6" => Seg_temp<=SEG_7(6); LED <=x"6";
WHEN x"7" => Seg_temp<=SEG_7(7); LED <=x"7";
WHEN x"8" => Seg_temp<=SEG_7(8); LED <=x"8";
WHEN x"9" => Seg_temp<=SEG_7(9); LED <=x"9";
WHEN OTHERS => Seg_temp<=SEG_7(0); LED <=x"0";
END CASE ;
END IF;
END PROCESS;
Seg_value<=Seg_temp;
-- Le signal sel est la concaténation des 4 entrées
sel <=IN4&IN3&IN2&IN1;
-- Activation des 3 Afficheurs BCD 7 Segments
TransEN1 <= '0';
TransEN2 <= '0';
TransEN3 <= '0';
END aCmpt;
Fichier de simulation :
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY Test_7SEG IS
END Test_7SEG;
ARCHITECTURE behavior OF Test_7SEG IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Process_LED
PORT(
clk : IN std_logic;
IN1 : IN std_logic;
IN2 : IN std_logic;
IN3 : IN std_logic;
IN4 : IN std_logic;
TransEN1 : OUT std_logic;
TransEN2 : OUT std_logic;
TransEN3 : OUT std_logic;
Seg_value : OUT std_logic_vector(7 downto 0);
LED : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal IN1 : std_logic := '0';
signal IN2 : std_logic := '0';
signal IN3 : std_logic := '0';
signal IN4 : std_logic := '0';
--Outputs
signal TransEN1 : std_logic;
signal TransEN2 : std_logic;
signal TransEN3 : std_logic;
signal Seg_value : std_logic_vector(7 downto 0);
signal LED : std_logic_vector(3 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Process_LED PORT MAP (
clk => clk,
IN1 => IN1,
IN2 => IN2,
IN3 => IN3,
IN4 => IN4,
TransEN1 => TransEN1,
TransEN2 => TransEN2,
TransEN3 => TransEN3,
Seg_value => Seg_value,
LED => LED
);
-- Stimulus process
stim_proc: process
begin
wait for 100 ns;
-- Crctère '1'
clk <= not(clk);
IN1<= '1';
IN2<= '0';
IN3<= '0';
IN4<= '0';
wait for 100 ns;
clk <= not(clk);
wait for 20 ns ;
-- Crctère '2'
clk <= not(clk);
IN1<= '0';
IN2<= '1';
IN3<= '0';
IN4<= '0';
wait for 100 ns;
clk <= not(clk);
wait for 20 ns ;
-- Crctère '3'
clk <= not(clk);
IN1<= '1';
IN2<= '1';
IN3<= '0';
IN4<= '0';
wait for 100 ns;
clk <= not(clk);
wait for 20 ns ;
-- Crctère '4'
clk <= not(clk);
IN1<= '1';
IN2<= '0';
IN3<= '1';
IN4<= '0';
wait for 100 ns;
clk <= not(clk);
wait for 20 ns ;
-- Crctère '7'
clk <= not(clk);
IN1<= '1';
IN2<= '1';
IN3<= '1';
IN4<= '0';
wait for 100 ns;
end process;
END;
Fichier des contraintes (Pinout.ucf) :
CONFIG VCCAUX = "3.3" ;
# Clock 12 MHz
NET "clk" LOC = P129 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz;
NET "Seg_value[0]" LOC = P117 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[1]" LOC = P116 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[2]" LOC = P115 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[3]" LOC = P113 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[4]" LOC = P112 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[5]" LOC = P111 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[6]" LOC = P110 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "Seg_value[7]" LOC = P114 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "TransEN1" LOC = P124 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12;
NET "TransEN2" LOC = P121 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "TransEN3" LOC = P120 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "IN1" LOC = P70 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "IN2" LOC = P69 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "IN3" LOC = P68 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "IN4" LOC = P64 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "LED[0]" LOC = P46 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "LED[1]" LOC = P47 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "LED[2]" LOC = P48 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
NET "LED[3]" LOC = P49 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12;
Photos du projet :
Téléchargement du projet FPGA 2 : Gestion de l’afficheur 7 Segments.
Un petit commentaire de vous, un Grand encouragement pour nous 🙂
– Bon Courage –