On désire implémenter sur une carte Nexys 3 un jouet robot capable de simuler l'endormissement. Son interface est la suivante :
Le jouet doit fonctionner de la façon suivante :
l'état du jouet est réévaluer toutes les 2 secondes, au rythme de l'horloge H.
lorsque le jouet est éveillé, ses yeux sont ouverts, et il rit.
lorsque le jouet est en état de sommeil léger, ses yeux sont fermés et il grogne.
lorsque le jouet est en état de sommeil profond, ses yeux sont fermés et il ronfle.
lorsque le jouet est en état de détresse, il pleure les yeux ouverts.
le jouet en état éveillé qu'on laisse à la lumière reste en état éveillé, même s'il y a du bruit.
pour mettre le jouet en état de sommeil léger, il faut partir de l'état éveillé, puis éteindre le lumière, en absence de bruit. Eteindre la lumière avec du bruit met le jouet en état de détresse.
lorsque le jouet est en état de détresse, il revient à l'état éveillé au prochain front d'horloge où la lumière est allumée, qu'il y ait du bruit ou non. Sinon, il reste en état de détresse.
lorsque le jouet est en état de sommeil léger, il passe en sommeil profond si la lumière continue d'être éteinte avec absence de bruit. Toute autre manipulation amène le jouet en état de détresse.
le jouet reste en état de sommeil profond tant que la lumière est éteinte et qu'il n'y a pas de bruit.
lorsque le jouet est en état de sommeil profond et que la lumière s'allume en absence de bruit, le jouet passe à l'état éveillé. Toute autre manipulation amène le jouet en état de détresse.
Nous allons d'abord concevoir le graphe d'états du jouet, qui sera de type Moore, puis le module correspondant et l'implémenter en SHDL (Simple Hardware Description Language) selon l'outil MDLE développé par Jean-Christophe Buisson au département Informatique de l'ENSEEIHT.
Les entrées sont notées dans l'ordre lumière - bruit(L - B) et les sorties yeux - voix(s[2] - s[1] - s[0]). D'après les spécifications énoncées ci-dessus, le jouet robot a 4 états possibles :
éveillé (yeux ouverts et il rit) ; sortie = 101 ; noté EV
sommeil léger (yeux fermés et il grogne) ; sortie = 010 ; noté SL
sommeil profond (yeux fermés et il ronfle) ; sortie = 000 ; noté SP
détresse (yeux ouverts et il pleure) ; sortie = 111 ; noté DE
Le graphe d'états est représenté sur la figure suivante :
Figure : Graphe de Moore du module
Voici la table de transition qui en résulte :
entrées
état avant
état après
00
101
010
01
101
111
10
101
101
11
101
101
00
111
111
01
111
111
10
111
101
11
111
101
00
010
000
01
010
111
10
010
111
11
010
111
00
000
000
01
000
111
10
000
101
11
000
111
Nous allons calculer de deux façons les relations entre les sorties et les entrées, la première assignation avec 2 bascules T et la seconde avec 2 bascules JK. Selon les règles heuristiques dont l'idée est de minimiser le nombre de bits qui changent (états ou sorties) lors des changements d'états, nous faisons l'assignation suivante :
L'outil MDLE permet de simuler le fonctionnement des circuits combinatoires et séquentiels. Il utilise le langage SHDL (Simple Hardware Description Language). Dans le but d'être pédagogique, son écriture est très simple et permet de concevoir des modules d'une manière plus condensée qu'avec d'autres langages habituels de description matérielle comme le VHDL. Pour plus d'informations sur la syntaxe, voir ici.
Voici le source robot_first.mdl correspondant au module conçu avec 2 bascules T :
Nous pouvons charger ce design grâce à l'éditeur graphique, ce qui donne :
Grâce au simulateur de MDLE, on peut parcourir le graphe de Moore en fonction du temps et des entrées. Ceci est illustré sur la vidéo suivante :
Nous allons dans un premier temps implémenter de manière hardware le design que nous avons conçcu ci-dessus. Le logiciel Xilinx ISE permet de faire cela en générant un fichier binaire (.bit) que l'on peut ensuite transférer depuis le PC vers la carte FPGA. Après cette première implémentation, nous allons créer une IHM permettant d'intéragir en temps réel avec la carte.
Le logiciel ISE permet de synthétiser le circuit séquentiel de notre module de robot jouet. Pour décrire ce design, ISE nécessite un fichier de description matérielle écrit en langage VHDL (plutôt utilisé en Europe) ou Verilog (plutôt utilisé aux US). Nous choisirons le langage VHDL car nous disposons d'un outil permettant de convertir un source SHDL en un source VHDL. Cet outil s'appelle SHDL2VHDL Converter et est téléchargeable ici : shdl2vhdl2.1.4.jar.
Utilisons à présent le source SHDL robot_second.mdl (design correspondant au paragraphe 2.4) et convertissons le en VHDL grâce à l'outil SHDL2VHDL, nous obtenons le source robot_second.vhd :
library IEEE; library UNISIM; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity robot_second is port(
l :instd_logic;
b :instd_logic;
h :instd_logic;
rst :instd_logic;
s2 :outstd_logic;
s1 :outstd_logic;
s0 :outstd_logic ); end robot_second;
architecture synthesis of robot_second is
-- internal signals declarations signal jx :std_logic; signal y :std_logic; signal x :std_logic; signal kx :std_logic; signal jy :std_logic; signal ky :std_logic;
begin
-- concurrent statements
jx <=(not l)and(not b)and(not y)and(not x);
kx <=(b and x)or(l and x);
jy <=(x and(not y))or((not l)and b and(not y));
ky <=(l and(not b)and y)or(l and(not x)and y);
s2 <=not x ;
s1 <=(x and(not y))or((not x)and y);
s0 <=not x ;
-- sequential statements process(h, rst)begin if rst ='1'then
x <='0'; elsif h'eventand h ='1'then
x <=((not kx)and x)or(jx and(not x)); endif; endprocess; process(h, rst)begin if rst ='1'then
y <='0'; elsif h'eventand h ='1'then
y <=((not ky)and y)or(jy and(not y)); endif; endprocess;
end synthesis;
Dans le projet ISE, Il nous faut maintenant un fichier permettant de faire le lien entre les signaux du source VHDL et les connecteurs d'entrée/sorties de la carte FPGA. Ce fichier s'appelle le "User Constraints File" (UCF). Nous choisissons les switch SW3, SW2, SW1 et SW0 pour respectivement les entrées reset (rst), clock (h), lumière (l) et bruit (b). Pour la sortie, nous utilisons les led LD2, LD1 et LD0 respectivement pour les sorties s2 (yeux), et (s1,s0) (voix). On a donc le fichier robot.ucf suivant :
# Inputs
NET "l" LOC = "T9";
NET "b" LOC = "T10";
NET "h" LOC = "V9";
NET "rst" LOC = "M8";
# Outputs
NET "s0" LOC = "U16";
NET "s1" LOC = "V16";
NET "s2" LOC = "U15";
Dans le projet ISE, nous ajoutons le source VHDL "robot_second.vhd" ainsi que le fichier de contraintes "robot.ucf". Nous pouvons maintenant générer le fichier .bit. Voici une capture écran :
Pour charger le fichier binaire depuis un terminal Linux, les commandes sont les suivantes :
Ici une image de la carte avec les entrées (rst, h, l, b) et les sorties de l'état initial (Eveillé : 101) :
Dans le design précédent, nous pouvons rajouter 3 afficheurs 7-segments pour les sorties ; c'est ce que nous avons fait dans ce source robotseg.vhd :
library IEEE; library UNISIM; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity robotseg is port(
l :instd_logic;
b :instd_logic;
h :instd_logic;
h1 :instd_logic;
rst :instd_logic;
an :inoutstd_logic_vector(0to3);
ss :outstd_logic_vector(0to2);
ssg :outstd_logic_vector(0to7) ); end robotseg;
architecture synthesis of robotseg is
-- clock
signal CTR :std_logic_vector(12downto0);
-- buffer signals declarations
signal ss_int :std_logic_vector(0to2);
-- internal signals declarations
signal jx :std_logic; signal y :std_logic; signal kx :std_logic; signal x :std_logic; signal jy :std_logic; signal ky :std_logic;
begin
-- concurrent statements
jx <=(not l)and(not b)and(not y)and(not x);
kx <=(b and x)or(l and x);
jy <=(x and(not y))or((not l)and b and(not y));
ky <=(l and(not b)and y)or(l and(not x)and y);
ss_int(2)<=not x ;
ss_int(1)<=(x and(not y))or((not x)and y);
ss_int(0)<=not x ;
Nous allons créer une interface contrôlant en temps réel la carte Nexys 3. Pour cela, il nous faut utiliser les fonctions bas-niveau de la librairie dpcutil. Elles nous permettront d'envoyer et de recevoir des signaux depuis la carte. Le design précédent doit être complété afin d'y inclure la communication USB. Les données d'entrée/sortie seront stockées sur le registre se situant à l'adresse 10 ("regEppAdr=1010" dans dpimref.vhdl). Le fichier de contraintes est pins.ucf. Après avoir généré et transféré le fichier .bit, nous utilisons l'IHM suivante écrite en C avec les librairies GTK/OpenCV :