Jacquot
TD et TP LO11
UTT 2014/2015
II.Saisir un schma
On va commencer par un exemple trs simple mais qui nous permettra de comprendre
comment l'environnement fonctionne.
Add wire
Icone
e1
Category : logic
Symbol : or2
s
e2
Add I/O Marker
Icone
On a deux entres que l'on va relier deux interrupteurs (sw0 et sw1 positionns
respectivement en L13 et L14) et une sortie qui va nous servir allumer une led (led0 en
F12).
Dans l'ordre, il est bon de commencer par les composants, puis par les connexions (wire)
pour terminer par les I/O Marker.
TD et TP LO11
UTT 2014/2015
Seul la documentation de la carte sur laquelle est votre FPGA vous permet de trouver
comment s'appellent les broches de votre FPGA pour les mettre dans le fichier ucf
correspondant. Cette documentation vous sera toujours fournie.
Notez que pour ouvrir un fichier ucf, il ne faut pas double-cliquer dessus : cliquer
simplement et aller chercher (sur la gauche) dans la fentre process :
User Constraints
|__ Edit constraints (text).
IV.Compilation
La compilation a comme objectif de raliser un fichier binaire (d'extension .bit) qui sera
tlcharg dans le FPGA. On clique dans la fentre projet sur le fichier le plus haut dans
la hirarchie (pour le moment ce sera notre schma) puis dans la fentre process on
choisit "Generate Programming File" (double clic)
V.Tlchargement
Le tlchargement dans la carte se fait avec Impact (trouv dans la fentre process) :
Configure Target Device
|__ Manage Configuration Project (Impact)
p est un nom de porte comme and, or, nor, nand, xor et xnor reprsentant le ET, le
OU, le OU-NON le ET-NON, le OU-Exclusif, et l'identit.
La suite est importante pour les projets un peu plus consquents et peut tre passe en
premire lecture.
edit -> Rename -> rename Selected net puis donner le nom puis OK.
2/94
TD et TP LO11
UTT 2014/2015
Pendant que vous y tes, il est possible de changer la taille de la feuille ou des feuilles.
Next
Donner un nom au symbole et ajouter le nom des entres et sorties puis next.
Remarque : Le "symbol wizard" permet de transformer directement votre schma en
cours en symbole si vous cochez "using schematic" et il vous trouve alors tout seul
l'ensemble des entres/sorties.
3/94
TD et TP LO11
UTT 2014/2015
INFO
I. Prsentation du sujet
Un schma prsente de manire symbolique ce que l'on cherche faire.
J1
"D14" "B4"
S3E J5
"B16" "D5"
"L13" "C12" "C4" "A6"
"L14" "D12" "A11" "E7"
"H18" "G9" "C14" "A4"
"N17" "A8" "A16" "C5"
"E13" "B6"
(J4):"B11"(J1):"F7"
FPGA #J4
sw0
sw1
sw2
sw3
a
b
c
d
e
f
g
a
f
c
d
0/1
Sortieselpour
slectionner
afficheur
sel
0000
0001
0010
0011
0100
0101
0110
0111
1000
II.Fichier ucf
Pour viter de chercher nous donnons quelques contenus du fichier ucf :
NET "SW<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ;
NET "SW<3>" LOC = "N17" | IOSTANDARD = LVTTL | PULLUP ;
4/94
1001
TD et TP LO11
UTT 2014/2015
Pour savoir comment sont connects nos afficheurs notre carte, il faut tlcharger la
documentation des afficheurs : dans google digilent pmodssd (donne un peu plus loin
dans ce document)
III.Table de vrit
Raliser la table de vrit correspondant au cahier des charges si on doit sortir un 1 pour
afficher un segment. Rflchissez sur la premire ligne avant de poursuivre.
sw3 sw2
sw1
sw0
IV.Synthse de la slection
Pour forcer des valeurs prdfinies :
5/94
TD et TP LO11
UTT 2014/2015
6/94
TD et TP LO11
UTT 2014/2015
INFO
e0
b0
b1
b2
b3
0
b4
b5
b6
b7
La valeur hexadcimale 56 est la valeur qu'il vous faudra utiliser dans la partie INIT
d'une (catgorie) LUT avec un composant lut3.
Pour initialiser une LUT, double cliquer dessus et remplir le champ INIT.
7/94
TD et TP LO11
UTT 2014/2015
a
f
c
d
III.Les multiplexeurs
INFO
Les multiplexeurs reprsentent une autre technique pour viter de simplifier et faire une
synthse. Encore une fois, la table de vrit suffit.
Soit donc la table de vrit suivante :
S2 S1
S0
D0
D1
D2
D3
D4
D5
D6
8/94
TD et TP LO11
UTT 2014/2015
D7
les entres de la table de vrit iront sur les entres de slections du multiplexeur
(S0,S1,S2)
Le problme est que la taille d'un multiplexeur augmente trs rapidement avec le
nombre d'entres.
Travail raliser : Utiliser un multiplexeur "m16_1e" en lieu et place d'une LUT
pour la synthse du segment a de la synthse prcdente. Ne pas oublier de mettre
l'entre E Vcc.
9/94
TD et TP LO11
UTT 2014/2015
# f segment :
NET "FX2_IO<27>" LOC = "A16" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
# g segment :
NET "FX2_IO<29>" LOC = "E13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
# CAT: digit selection :
NET "FX2_IO<31>" LOC = "B11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
10/94
TD et TP LO11
UTT 2014/2015
INFO
a
b
DEMI
ADD
an
bn
Rn-1
ADD
S
R
Sn
R
b
0
0
1
1
a
0
1
0
1
R
0
0
0
1
S=ab
R = a.b
S
0
1
1
0
bn an
Rn-1 00 01 11 10
0
0 0
1 0
1
0 1
1 1
Rn
bn an
Rn-1 00 01 11 10
0
0 1 0
1
1
1 0 1
0
Sn
Sn = an bn Rn-1
Remarquez que Rn n'est pas simplifi au mieux pour faire apparatre un OU exclusif.
Travail raliser
11/94
TD et TP LO11
UTT 2014/2015
Implanter un additionneur 1 bit avec deux ou-exclusifs deux entres et trois portes
NANDs. Pour les tests, les entres seront relies des interrupteurs et les sorties des
LEDs.
Copier 4 fois le schma prcdent et montrer que l'on peut raliser ainsi un additionneur
4 bits. N'oubliez pas que la somme de deux nombres de 4 bits peut donner un nombre
de 5 bits.
0 (00)2
-1
-2
Rin
Rout
-1
-1
-2
-1
Travail raliser
Raliser un schma du soustracteur en modifiant celui de l'additionneur en lui ajoutant
deux inverseurs.
12/94
TD et TP LO11
UTT 2014/2015
III.Additionneur 4 bits
Comme indiqu en introduction, si vous avez de l'arithmtique faire il faut mieux
utiliser des composants tout faits. En effet, tout FPGA moderne possde un certain
nombre de parties pr-cbles ralisant ces fonctions. On utilisera ainsi le composant
ADD4 dans la catgorie "arithmetic". Les entres de ce composant seront des interrupteurs
extrieurs mais ses sorties seront destines tre affiches sur un afficheur sept segments... et
c'est l que les choses se compliquent un peu.
Prparation
Montrer que dans le cas o la somme de deux nombres BCD sur 4 bits dpasse 9 (cette somme
n'est pas BCD mais binaire cause de ADD4), il suffit d'ajouter 6 au rsultat pour obtenir le
nombre BCD correct.
Travail raliser
On va se contenter d'utiliser le composant ADD4 de Xilinx dans le cas d'entres BCD.
Cela veut dire que chacune des entres ne peut dpasser (9)10=(1001)2.
On vous demande d'utiliser deux composants ADD4 de Xilinx pour obtenir la somme BCD (sur 5
bits) de deux nombres BCD (sur 4 bits). Le deuxime additionneur est l pour ajouter 6 en cas de
dpassement de 9. Il vous faut naturellement ajouter la logique capable de dtecter un
dpassement de 9. Un comparateur COMPM4 et un OU devraient suffire.
Les tudiants dbutants sont invits tester d'abord un additionneur ADD4 seul avec l'afficheur
7 segments, puis ajouter le comparateur COMPM4 et montrer que pour un rsultat qui
dpasse strictement 15 (autrement dit quand C0 vaut 1) le comparateur ne s'en rend pas
compte !!! d'o la prsence du OR2 qui rsout ce problme.
a
f
e
Schma complter
g
c
d
Afficheur + LED
CI
COMPM4
A0
A1
A2
A3
B0
B1
B2
B3
ADD4
S0
S1
S2
S3
A0
A1
A2
A3
dizaine
CI
GT
LT
B0
B1
B2
B3
OR2
>1
CO
13/94
A0
A1
A2
A3
B0
B1
B2
B3
ADD4
S0
S1
S2
S3
CO
TD et TP LO11
UTT 2014/2015
Pour Printemps 2015 : voir dessin TP1 sachant que l'on est connect en J5 !
IV.Additionneur/soustracteur 4 bits
L'additionneur soustracteur existe comme composant tout fait ADSU4 chez Xilinx, mais
nous allons le raliser partir de ADD4. pour en comprendre le fonctionnement de
manire intime, en particulier la notion de complment deux.
Prparation
Calculer les limites d'une reprsentation en complment deux sur 4 bits notes B 4 et (B4+1) dans la suite.
Si sel = 0 on additionne et le nombre rsultat se trouve en sortie du premier
additionneur sur 5 bits (ou en sortie du deuxime additionneur mais avec comme 5 bit
CO1 et non CO2)
Si sel = 1 les complments sont raliss et on additionne 1 l'aide de CI1. On fait donc
un complment deux de B = /B+1, mais on reste sur 4 bit. Le premier additionneur fait
donc S=A+/B+1=A-B. Montrer que si B dpasse B4+1, cela ne fonctionne plus. Prendre
par exemple B= B4+2 et faire son complment deux en montrant qu'alors le bit
gauche vaut 0 et qu'ainsi ce nombre ne peut tre interprt comme ngatif.
Dans le cas de la soustraction, Sel=1, montrer l'aide de quelques exemples qu'un
rsultat positif positionne CO1 1 tandis qu'un rsultat ngatif le positionne 0 (choisir
B entre 1 et B4+1 pour la soustraction).
Pour afficher le rsultat de la soustraction correctement sur un ventuel afficheur 7
segments et une diode LED de signe, il faut refaire un complment deux pour
retrouver la valeur absolue. C'est l'objet du deuxime additionneur. Ainsi, si rsultat
positif LED teinte et valeur absolue sur afficheur et si rsultat ngatif LED allume et
valeur absolue sur afficheur. Le schma complet est prsent ci-dessous.
Travail raliser
Chercher la fonction F du schma ci-aprs.
14/94
TD et TP LO11
UTT 2014/2015
Implanter l'ensemble et tester. Donner les plages pour lesquelles l'affichage du rsultat
d'une addition fonctionne correctement si le rsultat est considr comme binaire sur 5
bits (CO1,S3,S2,S1,S0). Comme il est sur 5 bits on ne peut pas l'afficher sur un ou deux
afficheurs
Tester si l'affichage d'une soustraction fonctionne correctement pour les valeurs
prcalcules dans la prparation en restant en binaire ou en utilisant un l'afficheur 7
segments.
Sel=0:addition
Sel=1soustraction
A0
A1
A2
A3
XOR2
=1
XOR2
=1
XOR2
=1
XOR2
=1
B0
B1
B2
B3
signe
CI1
CI2
ADD4
S0
S1
S2
S3
XOR2
=1
XOR2
=1
XOR2
=1
CO1
XOR2
=1
Trouver la fonction F
15/94
A0
A1
A2
A3
B0
B1
B2
B3
ADD4
S0
S1
S2
S3
CO2
TD et TP LO11
UTT 2014/2015
INFO
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
ENTITYdemoISPORT(
a:inSTD_LOGIC_VECTOR(3DOWNTO0);4entres
s:outSTD_LOGIC_VECTOR(1DOWNTO0));
2sorties
ENDdemo;
Il manque 13 lignes cette table, qui sont retires, mais donnent des 0 en sortie
Notez que la partie gauche de la table de vrit appele partie SI concerne les entres,
et la partie droite (appele ALORS) concerne les sorties. La donne d'une table de vrit
permet directement de trouver l'entit. Elle permet aussi d'crire directement
l'architecture avec un "with select when" :
1
2
3
4
5
6
7
8
ARCHITECTUREmydemoOFdemoIS
BEGIN
WITHaSELECT--style with select when
s<="11"WHEN"0101",-- premiere ligne
"01"WHEN"0110",-- deuxieme ligne
"10"WHEN"1101",-- troisieme ligne
"00"WHENOTHERS;-- pour les 13 lignes retires
ENDmydemo;
Travail raliser
exo1 : Refaire le transcodeur complet d'affichage sept segments du TP1. Ce transcodeur
sera utilis trs souvent par la suite, il sera donc important d'en mettre une copie de
ct et un symbol associ.
exo2 : Modifier l'exo1 pour grer une sortie de votre choix par une quation (le reste est
gr par un with select when). Il faudra naturellement aussi modifier le "with select
when" !
16/94
1
2
3
4
5
6
7
TD et TP LO11
UTT 2014/2015
devantentitajouter:useIEEE.STD_LOGIC_ARITH.ALL;
devantentitajouter:useIEEE.STD_LOGIC_UNSIGNED.ALL;
PROCESS(clk)BEGIN
IFclk'eventandclk='1'THENouIFrising_edge(clk)THEN
q<=q+1;
ENDIF;
ENDPROCESS;
Ce qui se trouve aprs le "IF clk'event" est une quation de rcurrence : q se trouve
gauche de l'quation et doit par consquent tre considr comme une sortie. Mais il se
trouve aussi droite, il doit par consquent tre considr comme une entre.
Les compteurs permettent de diminuer la frquence d'horloge. Vous pouvez complter
vos connaissances sur les compteurs en VHDL sur le site
http://fr.wikibooks.org/wiki/TD3_VHDL_Compteurs_et_registres
Travail raliser
Exo3 : Vous disposez d'une horloge 50MHz en broche "C9" de votre composant FPGA
SPARTAN 3E. Raliser l'aide d'un compteur 24 bits une horloge d'environ 3 Hz. Sortie
sur une LED, le clignotement de celle-ci doit tre visible l'il.
Indications
1
2
3
4
5
6
#====Clockinputs(CLK)====
NET"clk"LOC="C9"|IOSTANDARD=LVCMOS33;
#====DiscreteLEDs(LED)====
#ThesearesharedconnectionswiththeFX2connector
NET"LED<0>"LOC="F12"|IOSTANDARD=LVTTL|SLEW=SLOW|DRIVE=8;
NET"LED<1>"LOC="E12"|IOSTANDARD=LVTTL|SLEW=SLOW|DRIVE=8;
INFO
Idem
http://fr.wikibooks.org/wiki/TD3_VHDL_Compteurs_et_registres#Exercice_
2 avec un nombre de bits diffrent.
L'horloge que l'on vient de raliser sera utilise presque
systmatiquement par la suite. Vous pouvez donc la sauver et en faire un
symbol pour une rutilisation future.
Par abus de langage on appellera compteur dans la suite un lment squentiel qui
comporte une horloge mais qui ne compte pas forcment en binaire. Dans ce dernier
cas, son quation de rcurrence ne peut donc pas s'crire simplement l'aide d'une
simple addition.
17/94
TD et TP LO11
UTT 2014/2015
Nous avons gauche un diagramme d'volution, au centre un tableau tat prsent tat
futur et droite les tableaux de Karnaugh permettant de trouver les quations de
rcurrences.
quations de rcurrence :
Q += Q Q
1
Q0+
= /Q0
Voici les extraits importants du programme VHDL correspondant :
1
2
3
4
5
6
7
PROCESS(clk)BEGIN
IFclk'eventandclk='1'THENouIFrising_edge(clk)THEN
quationsdercurrencesici
q1<=q1xorq0;
q0<=notq0;
ENDIF;
ENDPROCESS;
INFO
Etat Futur
b c
d e
g a+ b+ c+ d+ e+ f+ g+
zero
1 1
1 1 1
un
1 1
0 0 0
deux
1 0
1 1 0
trois
1 1
1 0 0
quatre
1 1
0 0 1
1
18/94
TD et TP LO11
cinq
0 1
1 0 1
six
0 1
1 1 1
sept
1 1
0 0 0
huit
1 1
1 1 1
neuf
1 1
1 0 1
UTT 2014/2015
clk
cmpt7seg
process
process a
b
clk_lent
c
d
e
f
cmpt7seg
clk
process
etat_present
process
process
etat_futur
Init
clk_lent
Exo4 et 6
a
b
c
d
e
f
Exo5 et 7
Exo4 :
1) crire les quations logiques a+, b+, c+, d+ ,e+, f+, g+ en fonction des entres a,
b, c, d, e, f, g.
2) Il nous reste un problme important rsoudre, c'est l'initialisation. En effet, pour bien faire, il
faudrait tudier les 127-10=117 tats restants pour voir comment ils se connectent sur notre cycle.
C'est un travail important qu'il est impossible de raliser moins d'y passer 117 soires ( raison
d'une transition par soire) soit presque 4 mois !!!
Pour viter cela on va prvoir une entre d'initialisation appele Init au cas o la mise sous tension
on se trouve dans un tat non prvu. Cette entre fonctionnera de manire synchrone, lorsqu'elle
sera 1 un front d'horloge provoquera l'affichage du 0 en sortie du compteur.
crire maintenant les quations de rcurrence trouves en 2) en ajoutant convenablement l'entre
Init.
3) Vous tes prt maintenant crire le programme VHDL complet. crire ces quations
dans le langage VHDL. Implanter en utilisant et modifiant l'horloge ralise dans la
section 2 pour pouvoir l'utiliser dans le composant : on utilisera un process pour le
diviseur de frquence et un process pour le compteur donc une seule entit.
1
2
3
4
5
ENTITYcmpt7segIS
PORT(CLK_50MHz:INSTD_LOGIC;
a,b,c,d,e,f,g:OUTSTD_LOGIC);
oualors:s7segs:outstd_logic_vector(6downto0));
ENDcmpt7seg;
Vous venez ainsi d'apprendre assembler deux blocs avec des process. Le travail
d'assemblage de blocs est une tche qui sera souvent demande dans ces TPs. Elle
sera ralise avec une technique diffrente dans le prochain TP.
Exo5 : Refaire le mme travail avec une entre d'initialisation.
19/94
1
2
3
4
5
TD et TP LO11
UTT 2014/2015
ENTITYcmpt7segIS
PORT(CLK_50MHz,Init:INSTD_LOGIC;
a,b,c,d,e,f,g:OUTSTD_LOGIC);
oualors:s7segs:outstd_logic_vector(6downto0));
END cmpt7seg;
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
ENTITYcmptISPORT(
clk:INSTD_LOGIC;
q:INOUTSTD_LOGIC_VECTOR(1DOWNTO0));
ENDcmpt;
ARCHITECTUREacmptOFcmptIScommentviterlesequations
BEGIN
PROCESS(clk)BEGIN
IF (clk'EVENT AND clk='1') THEN
CASEqisstylecasewhen
WHEN"00"=>q<="01";premieretransition
WHEN"01"=>q<="10";deuxiemetransition
WHEN"10"=>q<="11";troisiemetransition
WHENOTHERS=>q<="00";quatriemetransition
ENDCASE;
ENDIF;
ENDPROCESS;
END acmpt;
ENTITYcmpt7segIS
PORT(CLK_50MHz:INSTD_LOGIC;
s_7segs:OUTSTD_LOGIC_VECTOR(6DOWNTO0));
END cmpt7seg;
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
20/94
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
TD et TP LO11
UTT 2014/2015
ENTITYcmptISPORT(
clk:INSTD_LOGIC;
q:OUTSTD_LOGIC_VECTOR(1DOWNTO0));
ENDcmpt;
ARCHITECTUREacmptOFcmptIScommentviterlesequations
SIGNALetat_present,etat_futur:STD_LOGIC_VECTOR(1DOWNTO0);
BEGIN
calculdel'tatfuturenfonctiondel'etatpresent
PROCESS(etat_present)BEGIN
CASEetat_presentisstylecasewhen
WHEN"00"=>etat_futur<="01";premieretransition
WHEN"01"=>etat_futur<="10";deuxiemetransition
WHEN"10"=>etat_futur<="11";troisiemetransition
WHENOTHERS=>etat_futur<="00";
ENDCASE;
ENDPROCESS;
lefuturdevientlepresent
PROCESS(clk)BEGIN
IF rising_edge(clk) THEN
etat_present<=etat_futur;
ENDIF;
ENDPROCESS;
sansarrt
q<=etat_present
END acmpt;
Exo7 : Refaire le mme travail que l'exo6 en utilisant un style deux "process" et en
grant l'initialisation. Votre programme aura trois process en fait puisqu'il faut ajouter la
division de frquence.
21/94
TD et TP LO11
UTT 2014/2015
e0
e1
e2
i1
e0e1
&
e2bar
i3
>1
i1
e0 e0
e0e1
s
e1 e1
&
e2 e
i2
1s
e2bar
i3
e0
>1s
i1
e0 e0
e0e1
s
e1
e1
&
e2 e
e1
i2
1s
e2bar
i3
e0
>1
e1
i2
Dans la figure de droite vous avez quatre rectangles. Il y aura donc dans votre projet
VHDL quatre entits et quatre architectures. Il y a un rectangle gris qui contient trois
rectangles bleus.
Passer du temps comprendre la figure ci-dessous : pour les "port map".
Voir aussi pour les explications :
http://fr.wikibooks.org/wiki/TD1_VHDL#Assembler_des_composants_en_VHDL
e0
e1
e2
i1
e0
e1
e
&
s e0e1
e0 e0
i3
e0
e2bar
>1
e1
e1
s S
e2
e1
e
i1
&
1
e0e1
e2bar
i3
e0
>1 s
e1
i2
i2
22/94
TD et TP LO11
UTT 2014/2015
tre vite. Un exemple important est celui des mmoires que nous allons aborder en
section 3.
ROMsUsingBlockRAMResources.
VHDLcodeforaROMwithregisteredoutput(template1)
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityrams_21ais
port(clk:instd_logic;
en:instd_logic;
addr:instd_logic_vector(5downto0);
data:outstd_logic_vector(19downto0));
endrams_21a;
architecturesynoframs_21ais
typerom_typeisarray(63downto0)ofstd_logic_vector(19downto0);
signalROM:rom_type:=
(X"0200A",X"00300",X"08101",X"04000",X"08601",X"0233A",
X"00300",X"08602",X"02310",X"0203B",X"08300",X"04002",
X"08201",X"00500",X"04001",X"02500",X"00340",X"00241",
X"04002",X"08300",X"08201",X"00500",X"08101",X"00602",
X"04003",X"0241E",X"00301",X"00102",X"02122",X"02021",
X"00301",X"00102",X"02222",X"04001",X"00342",X"0232B",
X"00900",X"00302",X"00102",X"04002",X"00900",X"08201",
X"02023",X"00303",X"02433",X"00301",X"04004",X"00301",
X"00102",X"02137",X"02036",X"00301",X"00102",X"02237",
X"04004",X"00304",X"04040",X"02500",X"02500",X"02500",
X"0030D",X"02341",X"08201",X"0400D");
begin
process(clk)
begin
if(clk'eventandclk='1')then
if(en='1')then
data<=ROM(conv_integer(addr));
endif;
endif;
endprocess;
endsyn;
23/94
TD et TP LO11
UTT 2014/2015
Travail raliser
Exo2 : dimensionner la ROM ncessaire votre problme. Calculer les valeurs
hexadcimales contenues dans cette ROM.
Raliser un compteur 4 bits avec initialisation asynchrone.
Reprendre le diviseur de frquence de la section 1
Assembler le tout
Init
clk_50MHz
Init
224
Compteur 4 bits
clk
Q(23)
'1' en
clk
FPGA
addr
ROM
data
a
a
b
f
g
c
d
e
e
f
d
g sel
b
c
24/94
TD et TP LO11
"B4"
"D5"
"A6"
"E7"
AA
AB
AC
P1
P2
P3
P4
560
AD
AA1
AB1
AC1
AD1
AE1
AF1
AG1
GND
Vcc
"A4"
"C5"
"B6"
"F7"
P1
P2
P3
P4
UTT 2014/2015
AE
AF
AG
C1
AA2
AB2
AC2
AD2
AE2
AF2
AG2
C2
GND GND
Vcc
Vcc
La broche de slection de l'afficheur note "sel" en tp1 est note "C" ici dans la
documentation officielle. On a reprsente en bleu la connexion de P1 (situe en broche
"B4") vers les deux segments a. C'est la mme ! Cela veut dire que si l'on veut afficher
deux valeurs diffrentes il faut les envoyer alternativement : c'est le rle du multiplexeur
qui est command par Q(19). Si un clignotement est prsent sur l'afficheur, on prendre
Q(18) voir Q(17) au lieu de Q(19). Il est important de comprendre pourquoi.
Init
lent
clk
C9
24
Init
s_Q23
Cmpt8bits
clk
sorties8
4
4
entreeFort entreeFaible
multiplexeur
sel
Affichage
4
binary
transcod7segs
FPGA
Affs7seg
sel
s7segs(6 downto 0)
25/94
TD et TP LO11
UTT 2014/2015
Travail raliser
Exo3 : Implanter l'ensemble prsent ci-dessus. Le dcodeur sept segments sera au
choix, la mmoire prcdente ou le dcodeur demand comme premier exercice de ce
TP. Le rsultat doit tre un affichage de 00 FF... Attention, le poids faible doit tre
droite !!!
Remarque :
Vous tes autoris utiliser l'outil de schmatique pour raliser cet exercice 3. Voici, par
exemple la ralisation de l'horloge lente :
vcc
s_vcc
CB16CE
CE
CB8CE
CE
Q[15:0]
CEO
TC
CLR
Q[7:0]
C
s_gnd
clk_slow(7:0)
CEO
TC
CLR
B8
clk
gnd
Le compteur 8 bits de l'exercice 3 peut alors tre ralis par une autre CB8CE.
Voici alors le schma de principe :
vcc
s_vcc
CB16CE
CE
C
CLR
CE
Q[15:0]
CEO
TC
clk_slow(7:0)
CB8CE
C
s_gnd
Q[7:0]
s_vcc
CEO
TC
CE
clk_slow(7)
CLR
s_gnd
clk
CB8CE
cmpt(7:0)
Q[7:0]
C CEO
TC
gnd
Mais pour le reste faites-le en VHDL.
Indication
Une aide pour implanter un multiplexeur peut tre trouve dans le polycopi de cours
p119 ou ici :
26/94
TD et TP LO11
UTT 2014/2015
https://fr.wikiversity.org/wiki/Very_High_Speed_Integrated_Circuit_Hardware_Description_
Language/Travail_pratique/TP_1#D.C3.A9codeur_8.C2.A0bits_vers_deux_afficheurs_avec
_sa_correction
27/94
TD et TP LO11
UTT 2014/2015
libraryieee;
useieee.std_logic_1164.all;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
compteurexo4TP5
entitycmptBCDisport(
clk:instd_logic;
init,en:instd_logic;
enout:outstd_logic;
s:outstd_logic_vector(3downto0)
);
endentity;
architecturebehaviorofcmptBCDis
signaln:std_logic_vector(3downto0);
begin
increment:process(clk,init)begin
ifinit='1'then
n<=(others=>'0');
elsifclk'eventandclk='1'then
ifen='1'then
ifn<9then
n<=n+1;
else
n<="0000";
endif;
endif;
endif;
endprocess;
s<=n;
process(n,en)begingestiondesortiecascadable
ifen='1'andn=9then
enout<='1';
else
28/94
35
36
37
38
TD et TP LO11
UTT 2014/2015
enout<='0';
endif;
endprocess;
endbehavior;
Travail raliser
Exo2 : Remplacer le compteur 8 bits de l'exercice 1 par un compteur BCD cascad
comme dans la figure ci-dessous :
en
en
Init
lent
clk
C9
224
horl_1
CmptBCD
Init
s_Q23
enout
clk
s_en en
InitCmptBCD
s_Q23 clk
enout
4
4
entreeFort
entreeFaible
sel
multiplexeur
Affichage
4
binary
transcod7segs
FPGA
Affs7seg
sel
s7segs(6 downto 0)
Nous avons invers "entreefaible" et "entreeFort" par rapport au schma prcdent mais
cela n'a absolument aucune consquence sur le VHDL.
Je mmorise :
Apprenez par cur ou sachez retrouver cette faon de grer un "reset" et un "ena"
(parfois aussi appel "en" pour enable). D'abord avec un "reset" synchrone :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
architecturebehaviorofcompteurbcdis
signaln:std_logic_vector(3downto0);
begin
increment:process(clk)begin
ifclk'eventandclk='1'then
ifreset='1'then
n<=(others=>'0');
elsifen='1'then
ifud='1'thenup
ifn<9then
n<=n+1;
else
n<=(others=>'0');
endif;
elsedown
29/94
TD et TP LO11
UTT 2014/2015
architectureBehavioralofCounter2_VHDLis
signaltemp:std_logic_vector(3downto0);
begin
process(Clock,Reset)begin
ifReset='1'then
temp<="0000";
elsif(Clock'eventandClock='1')then
ifen='1'then
iftemp="1001"then
temp<="0000";
else
temp<=temp+1;
ud
en
ud
en
ud
s_en en
CmptBCD
CmptBCD
Init
Init
enout
s_Q23
s_Q23 clk enout
clk
Init
lent
clk
C9
224
horl_1
4
4
entreeFort
entreeFaible
sel multiplexeur
Affichage
4
binary
transcod7segs
FPGA
Affs7seg
sel
s7segs(6 downto 0)
30/94
TD et TP LO11
UTT 2014/2015
Key=0
Key=1
Key=1
Ring=0
Ring=0
Off
Off
Armed
Off
Off
Ring=0
Ringing
Armed
Ring=1
Armed
La transition devient rceptive, c'est dire qu'elle dcrit ce qui se passe quand la
rceptivit est vraie et quand la rceptivit est fausse (donc suppression des oreilles de
Mickey)
Prparation
INFO
Relire le cours p136 141 sur la programmation d'une machine tats pour
essayer de comprendre comment programmer un graphe d'tats.
V. Le compteur de passages
Un ensemble de deux capteurs infrarouge peroit le passage d'une personne et en fonction de son
sens de passage incrmente ou dcrmente un compteur qui dcod affiche le nombre de
personnes sur deux afficheurs 7 segments.
Il nous faudra comme composants :
deux compteurs-dcompteurs dcimaux (cascads) ainsi que la logique d'affichage. C'est ce que
l'on a fait dans l'exercice exo3 prcdent.
une logique de contrle pour dtecter le sens de passage
Seule la logique de contrle est spcifie l'aide d'un graphe d'volution que voici.
31/94
init
TD et TP LO11
sequenceur
Init='1'
S1
Gauche='0'
S3
Gauche='1'
Gauche='0''
DU<='1'
EN<='1'
S4
='1'
Gauche='1'
='1'
Droite='1'
DU<='1'
EN<='0'
S6
clk_1Hz
du
DU<='0'
EN<='0'
Droite='0'
Droite='1'
Droite='0'
DU<='0'
S5
EN<='1'
DU<='1'
EN<='0'
S2
en
DU<='0'
EN<=01'
Gauche='1'
Droite='1'
UTT 2014/2015
DU<='0'
EN<='0'
S7
Remarques :
En cours p 137, les actions sont notes dans les tats. Il n'y a aucune diffrence entre les deux
notations.
Ce graphe ne fonctionne qu'avec un compteur qui compte quand "en" est un.
On appellera ce graphe d'volution squenceur ou machine tats
clk_lente
droite
gauche
Init
clk machine_a_etat
d
g
Init
divfreq
clk_50MHz
C9
clk
compteurbcd
compteurbcd
UD
UD
endiz
En
En
enout
enout
Init
Init
UD ud
En en
222
Q(17)
Q(23)
clk_out2 clk_out1
Compteur/dcompteur BCD
clk
clk_lente
unit
mux
addr
'1'
FPGA
en
clk
e0
sel
sel
clk
s
e1
dizaine
s
4
addr
mem
data(7 downto 0)
s(7 downto 0)
selaff
Compteur de passages
32/94
TD et TP LO11
UTT 2014/2015
Prparation
Que se passe-t-il si Droite et gauche arrivent en mme temps ? Modifier le graphe
d'volution pour grer seulement le cas Droite='1'&Gauche='0' d'une part et
Gauche='1'&Droite='0' d'autre part.
(Optionnel) Chercher le graphe d'tats correspondant au problme partir du graphe
d'volution donn.
(Optionnel) crire les quations de rcurrence faisant intervenir l'entre d'initialisation "Init" si vous
dsirez les utiliser, autrement passer directement la section suivante.
Travail raliser
Exo 4 :
Programmer directement avec un style "case when" votre squenceur.
On vous demande d'implanter le graphe d'tats en lui ajoutant l'ensemble compteur dcompteur de
l'exo 1 prcdent (et le processeur pour l'horloge lente).
Vous trouverez aussi une trs grande partie du code de ce squenceur dans le lien :
http://fr.wikibooks.org/wiki/TD5_VHDL_et_CAO#El.C3.A9ments_d.27implantation_en_VHDL
Je retiens :
Voici en condens comment on programme un graphe d'volution en style deux process :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
typestateis(S1,S2,S3,S4,S5,S6,S7);
signalnext_etat,reg_etat:state;
cettepartiedpenddugraphed'tat:ellegrelestransitions
combinatoire:process(etat,d,g)begin
caseetatis
whens1=> if(d='1'andg='0')then
next_etat<=s2;
elsif(g='1'andd='0')then
next_etat<=s3;
else
next_etat<=s1;
endif;
when s2=> ....
...............
whenothers=>next_etat<=s1;
endcase;
endprocess;
cettepartienechangepastantqueresetestasynchrone
sequenceur:process(clk,reset)begin
ifreset='1'then
etat<=s1;
elsifrising_edge(clk)then
etat<=next_etat;
endif;
endprocess;
cettepartiegrelessortiesavec"whenelse"ou"withselectwhen"
en<='1'whenetat=s4else
'1'whenetat=s5else
'0';
33/94
TD et TP LO11
UTT 2014/2015
34/94
TD et TP LO11
UTT 2014/2015
INFO
A partir de maintenant, nous allons utiliser un processeur dans nos FPGA. Le processeur
sera compltement fourni en VHDL : il s'agit d'un AVR compatible Tiny861 de chez
ATMEL.
Vous pouvez le trouver directement dans le fichier ressource LO11 du site "perso
moutou" dans le rpertoire TP7/Tiny861. On donnera le fichier microcontroleur.bit
I. Architecture
Architecture des registres mmoires
Il existe 3 espaces distincts en mmoire :
- Les 32 premires adresses correspondent aux 32 registres. Ces registres sont
directement relis l'ALU et tous les calculs ne peuvent tre effectus qu' partir de ces
registres (addition, soustraction, multiplication, oprations logiques, tests ).
- L'espace IO de l'adresse 0x20 0x5F. Dans cet espace se trouvent beaucoup de
registres de gestion du matriels (les ports, Timers, UART,...). Pour accder ces
registres les instructions in et out utilisent l'adresse 0 pour le premier registre et non
l'adresse 0x20. Les instructions cli et sbi permettent de mettre 0 ou 1 un bit d'un
registre
- Enfin partir de l'adresse 0x60 se trouve la mmoire proprement parler (le Tiny861
possde 512 octets de RAM). Pour accder tout l'espace mmoire (Registre et zone I/O
incluse) les instructions ST,LD et STS et LDS peuvent tre utilises. L'adressage peut
tre direct (STS ou LDS) ou indirect (ST et LD). Un adressage indirect utilise les registres
X, Y ou Z (respectivement les registres R27:R26, R29:R28 et R31:R30) pour pointer sur
une zone mmoire.
Quelques registres importants du banc de registres
Ce tableau (partiel) des registres respecte les fichiers d'inclusion du compilateur avr-gcc.
Par exemple, dans la documentation officielle, le bit b0 du PORTB s'appelle PORTB0
tandis que dans le fichier d'inclusion du GNU-C il s'appelle PB0.
Comme vous pouvez le constater, chaque registre est caractris par deux adresses.
Chacune des deux adresses est espace de 0x20=32. C'est le nombre de registres
usage gnral.
Notez que le fichier d'inclusion avr/io.h que l'on utilisera trs vite utilise les nombres qui
ne sont pas entre parenthses :
1
2
3
4
/*PortB*/
#definePINB _SFR_IO8(0x16)
#defineDDRB _SFR_IO8(0x17)
#definePORTB _SFR_IO8(0x18)
35/94
TD et TP LO11
Bit 6
UTT 2014/2015
Addr
Name
Bit 7
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
0x3F(0x5F)
SREG
0x32(0x52)
TCTN0L
0x2F (0x4F)
TCCR1B
CS11
CS10
0x2E (0x4E)
TCTN1
Timer1 8 bits
0x2D (0x4D)
OCR1A
0x2C (0x4C)
OCR1B
0x1B(0x3B)
PORTA
PC7
PC6
PC5
PC4
PC3
PC2
PC1
PC0
0x1A(0x3A)
DDRA
DDC7
DDC6
DDC5
DDC4
DDC3
DDC2
DDC1
DDC0
0x19(0x39)
PINA
PINC7
PINC6
PINC5
PINC4
PINC3
PINC2
PINC1
PINC0
0x18(0x38)
PORTB
PB7
PB6
PB5
PB4
PB3
PB2
PB1
PB0
0x17(0x37)
DDRB
DDB7
DDB6
DDB5
DDB4
DDB3
DDB2
DDB1
DDB0
0x16(0x36)
PINB
PINB7
PINB6
PINB5
PINB4
PINB3
PINB2
PINB1
PINB0
0x14(0x34)
TCNT0H
0x05 (0x25)
ADCH
0x04 (0x24)
ADCL
0x03(0x23)
UDR
0x02(0x22)
UCSRA
RXC
TXC
UDRE
FE
DOR
PE
U2X
MPCM
0x010x21)
UCSRB
RXCIE
TXCIE
UDRIE
RXEN
TXEN
UCSZ2
RXB8
TXB8
0x00(0x20)
TCCR1E
--
--
Bit 0
CS13
CS12
36/94
TD et TP LO11
UTT 2014/2015
Afficheurs
f
e
LEDs
g
c
d
J4"B11""D14""B16""C4""A11""C14""A16""E13"
Sel a b c d e f g
PORTB
PORTA
Tiny861
J5"A8""G9""D12""C12"
PINA
S3E"N17""H18""L14""L13"
Interrupteurs
37/94
TD et TP LO11
UTT 2014/2015
Nous avons dcid d'utiliser avr-gcc pour assembler (au lieu de avr-as). Cette
dcision a des consquences que nous n'expliquerons pas ici.
Programmation de la mmoire programme
La programmation de la mmoire programme peut tre ralise de plusieurs manires.
Si la manire la plus simple reste la transformation du programme en fichier VHDL, nous
n'utiliserons pas cette mthode bien trop lente : elle ncessite une recompilation globale
du projet, ce qui peut prendre quelques minutes. Nous allons plutt utiliser un utilitaire
data2mem comme indiqu dans la figure ci-aprs.
La commande qui fait cela est :
data2mem -bm memory.bmm -bd demo.elf -bt microcontroleur.bit -o uh microcontroleur
Ces contraintes sont dj prsentes dans le fichier ucf donn dans les ressources mais
sont en commentaires.
Le fichier memory.bmm ncessaire contiendra :
ADDRESS_SPACE prgmem RAMB16 [0x00000000:0x00001FFF]
BUS_BLOCK
prgmem/Mrom_PM_Drd_mux00002 [7:4] PLACED = X0Y3;
prgmem/Mrom_PM_Drd_mux00001 [3:0] PLACED = X1Y2;
prgmem/Mrom_PM_Drd_mux00004 [15:12] PLACED = X0Y2 ;
prgmem/Mrom_PM_Drd_mux00003 [11:8] PLACED
END_BUS_BLOCK;
END_ADDRESS_SPACE;
38/94
= X1Y3;
TD et TP LO11
s3e.ucf
dm.vhd
pm.vhd
microcontroleur.vhd
ISE
attiny861.bmm
UTT 2014/2015
prog.c
prog.S
avr-gcc
data2mem Xilinx
Utility
prog.elf
microcontroleur.bit
Chane de
compilation de
programme
Impact
Chane de
compilation Xilinx
Utilisation de data2mem
Prenez un peu de temps examiner cette figure. Il est important de toujours savoir ce
que l'on fait exactement mme sans en connatre les raisons exactes. Un script peut
faire tout cela de manire automatique :
#!/bin/bash
export PATH=$PATH:/usr/bin:/opt/Xilinx/11.1/ISE/bin/lin
cp ../microcontroleur.bit .
avr-gcc -mmcu=attiny861 exo1.S -o exo1.elf
data2mem -bm attiny861.bmm -bd exo1.elf -bt microcontroleur.bit -o uh
microcontroleur
INFO
TD et TP LO11
UTT 2014/2015
IV.Travail introductif
Comprendre la notion de PORT d'entre et de PORT de sorties
Voici un premier exemple de programme assembleur
#define __SFR_OFFSET 0 //obligatoire pour fonctionnement correct de "out" et "in"
.nolist
#include <avr/io.h>
.list
.section .text
.global main
main:
;
LDI
R16, 255
OUT
DDRB, R16
LDI
R16, 2
LDI
R17, 4
ADD
R16, r17
IN
R16, PINA
OUT
PORTA, R16
RJMP
main
; on recommence RJMP=GOTO
.END
Ce programme ne fait que recopier l'tat des interrupteurs (PINA) sur les LEDs (PORTA).
Un certain nombre d'instructions ont t volontairement laisses en commentaire (qui
rappelons-le, commencent par un ; ). Intressez-vous seulement ce qu'il y a entre
main : et .END
Indications
Opration
ADD
Rd, Rr
Flags
#Clocks
Additionne deux
registres
Rd Rd+Rr
Z,C,N,V,H
Charger en immdiat
Rd K
None
LDI
Rd, K
IN
Rd Port
None
OUT
Port Rr
None
RJMP
Saut relatif
PC PC + k + 1
40/94
None
TD et TP LO11
UTT 2014/2015
Travail raliser
Faites tourner le programme ci-dessus dans votre processeur (qui sera dans le FPGA).
Si vous avez souvenir de quelques instructions assembleur, vous pouvez essayer de
faire autre chose que la recopie sur vos LEDs
V.Travaux pratiques
Travail raliser (Exercice 1)
On ralisera un programme qui ralise une addition de 255 et de 1 et qui sort le registre
de statut (SREG) sur les Leds (PORTA). Si vous voulez savoir ce qui sort, la seule
solution est de sortir dans PORTB sur les afficheurs 7 segments.
Indication : Le registre SREG peut tre accd comme un PORT par les instructions IN
et OUT.
R16
; Complement
NEG
R16
; 2's complement
TST
AND
OR
ADD
R16
R16, R17
R16, R17
R16, R17
; bitwise AND
; bitwise OR
; summing
Indications : Un des deux registres peut tre charg l'aide des interrupteurs.
Mnemonics Operands Description
ADD
Rd, Rr
Opration
Flags
Additionne deux
registres
Rd Rd+Rr
Z,C,N,V,H
#Clocks
1
AND
Rd, Rr
Registres du ET
logique
Rd Rd * Rr
Z,N,V
ANDI
Rd, K
Registres du ET
logique et constante
Rd Rd * K
Z,N,V
OR
Rd, Rr
Registres du OU
logique
Rd Rd v K
Z,N,V
41/94
TD et TP LO11
UTT 2014/2015
ORI
Rd, K
Registres du OU loque Rd Rd v K
et constante
Z,N,V
EOR
Rd, Rr
Registres du OU
exclusif
Rd Rd Rr
Z,N,V
COM
Rd
Complment logique
Rd 0xFF - Rd
Z,C,N,V
NEG
Rd
Rd 0x00 - Rd
Z,C,N,V,H
TST
Rd
Rd Rd * Rd
Z,N,V
Ngation
Test du zero ou du
mini
R16, 10
MOV
R17, R16
NEG
R16
ADD
; load number
; 2's complement
R17, R16
Indication :
Mnemonics Operands Description
MOV
Rd, Rr
Opration
Copier un registre
dans un autre
Rd Rr
Flags
#Clocks
None
1
ret
Montrer qu'un tel delay est encore trop rapide. Pour avoir un temps correct il faudra le
faire environ 0x40 fois.
Indication 2 :
42/94
TD et TP LO11
SUB
Rd, Rr
Opration
UTT 2014/2015
Flags
Soustraire deux
registres
RdRd - Rr
Z,C,N,V,H
#Clocks
1
SUBI
Rd, K
Soustraire les
constantes de deux
registres
RdRd - K
Z,C,N,V,H
SBIW
Rdl, K
Soustraction
immdiate du mot
Rdh:RdlRdh:Rdl - K
Z,C,N,V,S
BRNE
INC
Rd
Incrmente
Rd Rd + 1
Z,N,V
DEC
Rd
Dcrmente
Rd Rd - 1
Z,N,V
BRNE
RET
RCALL
PC STACK
None
PC PC + k + 1
None
Indication 3 :
delay:
ldi r23, 0x40 ; sur Spartan3e
delayloop_ext:
ldi r24, 0xff
brne delayloop
dec
; branch if not 0
r23
brne delayloop_ext
ret
TD et TP LO11
UTT 2014/2015
Indication : Si l'instruction lsl est applique dans une boucle, le '1' finit par
disparatre !!!!
Mnemonics Operands Description
Opration
Flags
#Clocks
LSL
Rd
dcalage gauche
Rd(n+1)Rd(n),Rd(0)
0
Z,C,N,V
LSR
Rd
dcalage droite
Rd(n)Rd(n+1),Rd(7) Z,C,N,V
0
BRNE
Puis aller chercher sans arrt ces valeurs dans la RAM avec l'instruction LD R16,Y+
sachant que Y=R29:R28.
Indications : La SRAM dans un ATMega8/16 va de l'adresse 0x0060 0x045F. La SRAM
d'un ATTiny26/46/86 commence partir de l'adresse 0x0060. Sa fin dpend de la srie
(128/256/512 octets) 0x0DF/0x015F/0x25F
Mnemonics Operands Description
Opration
LDI
Rd, K
Charger en immdiat
STS
K, Rr
Stockage direct de
SRAM
Flags
#Clocks
Rd K
none
(k) Rr
None
44/94
TD et TP LO11
UTT 2014/2015
Initialisation RAM
LDI / STS
Initialisation Y
CLR R29
LDI R28,0x60
R16 [ Y++]
LD R16,Y+
R28 = 0x68 ?
CPI R28,0x68
BRNE suite
R28 0x60
PORTA R16
DELAY
RCALL delay
3) Ralisez les chenillards que vous dsirez (K2000 ou autre) avec la technique de votre
choix.
#define__SFR_OFFSET0
#include<avr/io.h>
mais
STS PORTC+0X20,R16
45/94
TD et TP LO11
UTT 2014/2015
Si on utilise seulement
1
#include<avr/io.h>
alors on crit :
OUT PORTC-0x20, R16
mais
STS PORTC,R16
Nous prfrons la premire solution et nous vitons du coup d'utiliser STS pour les SFRs.
46/94
TD et TP LO11
UTT 2014/2015
INFO
Cette liaison a 3 fils est une liaison minimum. Elle ncessite une collaboration logicielle
active entre les 2 machines pour contrler le transfert des informations. Un mcanisme
souvent utilis est le protocole XON XOFF.
Notre hyperterminal sera gtkterm configur comme ci-dessous ( part peut-tre le
PORT) :
PORT :/dev/ttyS1, vitesse : 19200, Parit : none, Bits 8, Bit de stop : 1, contrle de flux :
none
N'oubliez pas de dfinir serial_out dans votre fichier ucf : un des signaux ci-dessous :
# ==== RS-232 Serial Ports (RS232) ====
NET "RS232_DCE_RXD" LOC = "R7" | IOSTANDARD = LVTTL ;
NET "RS232_DCE_TXD" LOC = "M14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ;
#NET "RS232_DTE_RXD" LOC = "U8" | IOSTANDARD = LVTTL ;
#NET "RS232_DTE_TXD" LOC = "M13" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ;
47/94
TD et TP LO11
UTT 2014/2015
II.Ralisation pratique
Ce que l'on va faire maintenant ne peut tre ralis qu'avec un processeur dans un FPGA
ou ASIC. Car :
Sur le tiny861 du commerce, il n'y a pas de liaison srie. Nous allons en
ajouter une en utilisant des registres qui ne sont pas destins cela dans
le processeur du commerce.
en_16_x_baud
uart_tx
bbfifo_16x8
data_in
write_buffer
reset_buffer
data_in
write
read
reset
clk
data_out
data_present
full
half_full
kcuart_tx
data_in
send_character
en_16_x_baud
clk
serial_out
serial_out
tx_complete
buffer_full
buffer_half_full
clk
Le schma ci-dessus fait apparatre 3 rectangles, il est donc compos de trois entits
(dont les noms sont en gras) et de trois architectures. La partie gauche est un buffer de
16 donnes de 8 bits : si vous insrez les trois fichiers dans votre projet, la connexion
indique dans le schma ci-dessus est toute faite. On peut trouver ces fichiers dans les
ressources tlchargeables dans le site perso de S.Moutou.
2) Raliser l'horloge "en_16x_baud" de la liaison srie
Ceci sera ralis comme indiqu dans le schma un peu plus loin.
Exercice de prparation
Le compteur mod_m_counter est configurer. Pour se faire, il faut savoir que l'on va
travailler 19200 bauds et que la frquence d'horloge est de 50 MHz. En dduire la
valeur mettre dans le generic de ce compteur.
INFO
48/94
Init
clk_50MHz
TD et TP LO11
clk
reset
clk
en
max_tick
q(N-1 downto 0)
uart_tx
reset_buffer
en_16_x_baud
mod_m_counter
open
UTT 2014/2015
data_in
clk
write_buffer
serial_out
buffer_full
buffer_half
open
open
serial_out
Une fois le compteur connect il faut se pencher sur l'interfaage de l'ensemble comme
un registre.
3) Comment interfacer des PORTs/Registres dans l'ATTiny861
La ralisation des PORTs PORTA et PORTB utiliss dans le TP prcdent se fait dans un
process que l'on trouve dans microcontroleur.vhd
L'ide gnrale est simple : un grand case qui slectionne les sorties en fonction des
adresses. Dans notre cas particulier on voit sur le dessin qu'il faut que l'on s'occupe de
"data_in" et de "write_buffer". Le mieux est de :
- relier "data_in" "IO_Dwr" sans condition
- relier "en" "IO_wr" quand l'adresse est celle de UDR avec une criture du type :
s_en <= IO_wr when (IO_A = UDR) else '0'; -- write UART UDR (UDR constante
-- prdfinie)
en dehors du case et des process.
4) Travail raliser (exercice 1)
Raliser la partie matrielle demande et montrer que l'on peut envoyer un caractre
constant (pas trop vite quand mme).
Indication : L'envoi d'un caractre par la liaison srie se fait par la simple instruction :
OUT UDR,R16
Mais ceci ncessite de dfinir UDR pour l'assembleur ! Voici comment on fait :
#define UCSRB
_SFR_IO8(0x01)
#define UCSRA
_SFR_IO8(0x02)
#define UDR
_SFR_IO8(0x03)
// UCSRA
#define RXC 7
#define TXC 6
#define UDRE 5
//UCSRB
#define RXEN 4
#define TXEN 3
49/94
TD et TP LO11
UTT 2014/2015
l'UTT
delayloop_ext:
ldi r24, 0xff
; decrement r25:r24
brne delayloop
dec
; branch if not 0
r23
brne delayloop_ext
ret
On testera les communications avec gtkterm (application Linux) configur comme cidessous ( part peut-tre le PORT) :
PORT :/dev/ttyS0, vitesse : 19200, Parit : none, Bits 8, Bit de stop : 1, contrle de flux :
none
Voici en dessin ce que l'on cherche faire :
microcontroleur.vhd
iowr: process(I_CLK)
PORTA
IO_DWr[7:0]
PORTB
clk
rst
sw[7:0]
in_PINB[7:0]
leds[7:0]
Aff7segs[7:0]
IO_A[5:0]
rst
rst
mod_m_counter
reset
clk
max_tick
q(N-1 downto 0)
open
uart_tx
reset_buffer
en_16_x_baud
clk
write_buffer
serial_out
s_en
s_en <= IO_wr when (IO_A = UDR) else '0';
50/94
8
serial_out
data_in
buffer_full
buffer_half
open
TD et TP LO11
UTT 2014/2015
microcontroleur.vhd
iowr: process(CLK)
PORTA
IO_DWr[7:0]
PORTB
clk
rst
sw[7:0]
in_PINB[7:0]
leds[7:0]
Aff7segs[7:0]
s_UCSRB
UCSRB
IO_A[5:0]
rst
rst
mod_m_counter
reset
clk
max_tick
q(N-1 downto 0)
open
uart_tx
reset_buffer
en_16_x_baud
clk
write_buffer
serial_out
s_en
8
serial_out
data_in
buffer_full
buffer_half
open
s_en <= IO_wr and s_UCSRB(3) when (IO_A = UDR) else '0';
Il manque le process "iord" qui est donn
- TXC et UDRE sont les bits b6 et b5 du registre UCSRA et la partie VHDL qui gre ce
registre ressemblera donc :
1
iord:process(IO_rd,IO_A,In_PINB,sw)
51/94
2
3
4
5
6
7
TD et TP LO11
UTT 2014/2015
begin
addressesfortinyX6device(useiom8.h).
ifIO_rd='1'then
caseIO_Ais
whenUCSRA=>IO_Drd<=('0'¬s_full¬s_full&"00000");
microcontroleur.vhd
iord: process
uart_tx
data_in
write buffer buffer_full
s_full
reset
clk
open
buffer_half_full
Initialisation RS232
2) Raliser un programme qui lit
sans arrt les switchs et envoie
sur la RS232 leur valeur
seulement lorsqu'ils ont chang.
Pour raliser cet exercice vous
allez procder en deux temps :
Initialisation R17
R16 PINA
IO_Drd
R16 = R17 ?
APPEL envoi_serie
CP R16,R17
BREQ suite
RCALL serial_tx
R17 R16
52/94
TD et TP LO11
UTT 2014/2015
2-2) Modifier le sous programme serial_tx pour qu'il envoie maintenant deux
caractres correspondant la valeur hexadcimale des interrupteurs.
Indication : voici comment on procde l'envoi d'un caractre hexadcimal
correspondant la valeur des poids faibles :
;**** poids faible
MOV R18,R16 ; pour garder la valeur de R16
ANDI R18,0x0F
CPI
R18,0x0A
Faites la mme chose avec les poids forts. Le fin du fin serait d'ajouter un espace pour
sparer les futures valeurs. Essayez avec :
wait:
SBIS UCSRA,UDRE
RJMP wait
LDI R18,' ' ; pour sparer la suite
OUT UDR,R18
Opration
Flags
BRCC
LSL
Rd
dcalage gauche
RetenueRd(n),
Rd(0) 0
53/94
#Clocks
Z,C,N,V
1
TD et TP LO11
UTT 2014/2015
54/94
TD et TP LO11
UTT 2014/2015
INFO
delay:process(clk)begin
ifrising_edge(clk)then
IO_rd_d<=IO_rd;
endif;
endprocess;
s_buffer_read<=IO_rd_dands_UCSRB(4)when(IO_A=UDR)else'0';read
UARTUDR
iord:process(IO_rd,IO_A,In_PINB,sw)
55/94
2
3
4
5
6
7
8
TD et TP LO11
UTT 2014/2015
begin
addressesfortinyX6device(useiom8.h).
ifIO_rd='1'then
caseIO_Ais
whenUCSRA=>IO_Drd<=(s_RXC¬s_full¬s_full&
"00000");
whenUDR=>IO_Drd<=s_in_UDR;
#include"avr/io.h"
#undefF_CPU
#defineF_CPU50000000UL
#include"util/delay.h"
1
2
3
4
5
6
7
8
9
10
//************************************************************************
//functionuart_init()
//purpose:putcharacterinfirstrs232PORT
//arguments:
//correspondingcharacter
//return:
//note:19200,8,n,1hardcoded:transmissionandreception
//************************************************************************
voidusart_init(void){
UCSRB=(1<<TXEN)|(1<<RXEN);//transmissionetreception
#defineUCSRB _SFR_IO8(0x01)
#defineUCSRA _SFR_IO8(0x02)
#defineUDR _SFR_IO8(0x03)
//UCSRA
#defineRXC7
#defineTXC6
#defineUDRE5
//UCSRB
#defineRXEN4
#defineTXEN3
voidusart_init(void);
voidusart_send(unsignedcharch);
charusart_receive(void);
//***********************************************************************
//main
//***********************************************************************
intmain(void){
charch;
usart_init();
while(1){
//echosimple
ch=usart_receive();
usart_send(ch);
_delay_ms(500);//onverrapasserlescaractres
}
return0;
}
56/94
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
TD et TP LO11
UTT 2014/2015
//UCSRC=(1<<UCSZ1)|(1<<UCSZ0)|(1<<URSEL);//ignorparnotrematriel
//UBBRL=0x33;//paspournouscar38400baudsSans8,2
}
//************************************************************************
//functionuart_receive()
//purpose:readcharacterinsecondrs232PORT
//arguments:
//correspondingcharacter
//return:nonblockingsubreturn1ifnodatapresentelsereturnchar
//note:19200,8,n,1hardcoded,nonblockingsubreturn0ifnodatapresent
//************************************************************************
charusart_receive(void){
while(!(UCSRA&(1<<RXC)));//attentetantquepasDataPresent
returnUDR;
}
//************************************************************************
//functionuart_send()
//purpose:putcharacterinfirstrs232PORT
//arguments:
//correspondingcharacter
//return:
//note:19200,8,n,1hardcoded
//initialisationuartprealablerequise
//************************************************************************
voidusart_send(unsignedcharch){
while(!(UCSRA&(1<<UDRE)));
UDR=ch;
}
57/94
TD et TP LO11
UTT 2014/2015
microcontroleur.vhd
iowr: process(CLK)
PORTA
IO_DWr[7:0]
PORTB
clk
rst
sw[7:0]
in_PINB[7:0]
rst
UCSRB
mod_m_counter
reset
clk
max_tick
q(N-1 downto 0)
leds[7:0]
Aff7segs[7:0]
s_UCSRB
serial_out
s_en_16_x_baud
open
IO_A[5:0]
iord: process
uart_rx
serial_in serial_in
s_in_UDR UDR[7:0]
data_out
s_en_16_x_baud en_16_x_baud
s_buffer_read read_buffer buffer_data_present s_RXC(7)
IO_Drd
UCSRA[7:0]
rst
reset_buffer
buffer_full open
serial_in
buffer_half_full open
clk
IO_rd
IO_rd_d
clk
s_buffer_read <= IO_rd_d and s_UCSRB(4) when (IO_A = UDR) else '0';
58/94
TD et TP LO11
UTT 2014/2015
vers le programme de chargement. Un 'L' sera affich sur les afficheurs dans ce cas mais
un 'U' dans le cas d'un non chargement.
Raliser le programme complet : ce programme passe en mode programmation et
attend alors 16 donnes et les met dans la mmoire la place des autres.
Une fois que toute la partie matrielle est en place, il vous faut raliser un fichier binaire
de 16 valeurs pour remplir la RAM. On vous propose le fichier C++ suivant :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/***tpmemo.cpp***/
#include<stdio.h>
#include<string.h>
charvalhex(characonv){
staticcharhex[17]="0123456789ABCDEF";
chari;
i=0;
while(aconv!=hex[i])i++;
returni;
}
main(){
FILE*sortie;
staticcharhexa[17]="0123456789ABCDEF";
chartrame[128],nomfichier[34];
unsignedcharnval,i,tab[255];
printf("****************************************************");
printf("\n*****Conversionvaleur>fichierIntelHEX*****");
printf("\n********TPprogrammationdememoires************");
printf("\n********Version0.1(S.Moutou&Cie)***********");
printf("\n****************************************************");
printf("\n\nCombiendevaleursvoulezvousentrer?");
scanf("%d",&nval);
for(i=0;i<nval;i++){
printf("%dvaleur(enhexadecimal):",i+1);
scanf("%x",&tab[i]);
}
printf("\nQuelestvotrenomdefichierdesauvegarde?(extension.bin)");
scanf("%s",nomfichier);
sortie=fopen(nomfichier,"w");
fwrite(tab,1,16,sortie);
fclose(sortie);
}
*****
********
TP programmation de memoires
************
********
***********
****************************************************
Combien de valeurs voulez-vous entrer ? 16
1 valeur (en hexadecimal) : 81
59/94
TD et TP LO11
UTT 2014/2015
60/94
TD et TP LO11
UTT 2014/2015
voidaffiche(uint8_tnb){
uint8_t tab[10]={0x3F,... a complter ....}; // segment a poids faible
uint8_t i; // compteur de boucle
for (i=0;i<25;i++) {
PORTB = tab[nb & 0x0F] & 0x7F; // mettre a 0 poids fort=selection
_delay_ms(????);
//continueraveclepoidsfort(unpeuplusdifficile?)
61/94
Initialisation RAM
Initialisation Y
TD et TP LO11
serial_rx
LDI / STS
CLR R29
LDI R28,0x60
R16 PINB
Pour flag Z
R16 = 0x00 ?
UTT 2014/2015
Initialisation X
ANDI R16,0xFF
IN r16,UDR
not_programming_mode
R16 [ Y++]
R28 = 0x70 ?
[X+] r16
CPI R28,0x70
BRNE suite
ST X+,r16
Decompte boucle
DEC R17
BRNE rcve
R28 0x60
finit ?
RET
PORTC R16
DELAY
RCALL delay
Vous pourrez peaufiner ce code pour l'affichage demand : 'L' si chargement et 'U' dans
les autres cas.
PORT :/dev/ttyS0, vitesse : 19200, Parit : none, Bits 8, Bit de stop : 1,
contrle de flux : none
INFO
62/94
TD et TP LO11
UTT 2014/2015
INFO
La liaison PS2 est (ou devrait-on dire tait) utilise pour la communication entre claviers
et souris et ordinateurs PC. L'objectif de ce TP est de raliser un dcodage des
informations provenant d'un clavier.
Reset
ps2d
ps2c
clk
ps2d
dout
rx_done_tick
En
clk
ps2c
Registre
affichage
Reset
sigAAfficher
clk
sel
MUX2/1
Exo3 TP5
224
Q(23)
Q(19)
63/94
TD et TP LO11
UTT 2014/2015
avr_fpga_spartan3.vhd
io.vhd
I_CLK_50
I_CLR
I_RX
I_SWITCH[7:0]
I_CLK
I_CLR
I_ADR_IO[7:0]
I_DIN[7:0]
I_SWITCH[7:0]
I_RD_IO
I_RX
I_WE_IO
Q_INTVEC[5:0]
Q_TX
Q_7_SEGMENT[6:0]
Q_LEDS[7:0]
Q_AN[3:0]
Q_TX
iord: process(I_ADR_IO,...
I_SWITCH[7:0]
I_ADR_IO[7:0]
PINB
(0x36)
UCSRC
(0x40)
UDR
(0x2C)
Q_DOUT[7:0]
TD et TP LO11
UTT 2014/2015
- "full"
- "half_full"
Ces signaux doivent tre lus par le processeur et ainsi formeront un PORT d'entre. Nous
allons les relier PINC.
Les donnes "data_out" sont aussi lire par le processeur. Elles seront relies PIND.
Voyons comment tout cela est ralis pour la lecture des donnes.
io.vhd
I_CLR
+ps2d
+ps2c
I_clk
iord: process
Programme VHDL donn s_dout bbfifo_16x8
dout
data_in
Reset
s_data_present 7
data_present
rx_done_tick
write
s_buffer_full 6 PINC[7:0]
ps2d
full
read
ps2c
half_full s_half_full 5
reset
PIND_DATA
PIND[7:0]
clk
data_out
clk
s_rx_done_tick
L_RD_FIFO
Remarquez les +ps2c et + ps2d qui signifient qu'il faut ajouter ps2c et ps2d l'entit de
io.vhd et les propager dans le composant global. Le "en" de lecture du clavier ps/2 est
positionn '1'. Les signaux sont dessins en rouge et sont dclarer.
Pour la sortie des informations on se contentera du PORT qui est reli aux LEDs (TP
prcdent).
Quelques informations supplmentaires sur le VHDL correspondant :
1
2
3
utilisdansleregistrePINCenlecture
b7b6b5
signals_data_present,s_buffer_full,s_half_full:std_logic;
iord:process(I_ADR_IO,I_SWITCH,
U_RX_DATA,U_RX_READY,L_RX_INT_ENABLED,
U_TX_BUSY,L_TX_INT_ENABLED)
begin
addressesformega8device(useiom8.hor#define__AVR_ATmega8__).
caseI_ADR_IOis
whenX"33"=>Q_DOUT<=PINC:
s_data_presentdatapresent?
&s_buffer_fullbufferplein?
&s_half_fullbuffermoitiplein?
&'0'nonutilis
&'0'nonutilis
&'0'nonutilis
65/94
15
16
17
TD et TP LO11
UTT 2014/2015
&'0'nonutilis
&'0';nonutilis
whenX"30"=>Q_DOUT<=PIND_DATA;PIND:
Nous n'avons pas mis l'ensemble du process ici mais seulement ce qu'il y a de nouveau
pour cet exercice.
Il y a un autre point sur lequel il nous faut revenir : la construction du signal read qui va
au FIFO. Il se fait avec le simple code :
1
L_RD_FIFO<=I_RD_IOwhen(I_ADR_IO=X"30")else'0';readPIND
#include"avr/io.h"
#undefF_CPU
#defineF_CPU25000000UL
#include"util/delay.h"
#defineRXDP7//RXDP:datapresentenrceptiondansFIFO
//***********************************************************************
//main
//***********************************************************************
intmain(void){
unsignedcharportc,portd;
while(1){
portc=PINC;//lectureduPORTCpourvoirsidonne?
if(portc&(1<<RXDP)){//sidatapresent
portd=PIND;
PORTB=portd;//sortiesurles8LEDs
}
_delay_ms(1000);//onverrapasserlescaractres
66/94
19
20
21
TD et TP LO11
UTT 2014/2015
}
return0;
}
#include"avr/io.h"
#undefF_CPU
#defineF_CPU25000000UL
#include"util/delay.h"
//************************************************************************
//functionuart_init()
//purpose:putcharacterinfirstrs232PORT
//arguments:
//correspondingcharacter
//return:
//note:38400,8,n,2hardcoded:transmissiononly
//************************************************************************
voidusart_init(void){
UCSRB=(1<<TXEN);//transmission
//UCSRC=(1<<UCSZ1)|(1<<UCSZ0)|(1<<URSEL);//ignorparnotrematriel
//UBBRL=0x33;//paspournouscar38400baudsSans8,2
}
//************************************************************************
//functionuart_send()
//purpose:putcharacterinfirstrs232PORT
//arguments:
//correspondingcharacter
//return:
//note:38400,8,n,2hardcoded
//************************************************************************
voidusart_send(unsignedcharch){
while(!(UCSRA&(1<<UDRE)));
UDR=ch;
}
intmain(void)
{
usart_init();//pourpouvoirdclencherinterruptionRS232
for(;;){
usart_send('A');
_delay_ms(1000);
67/94
38
39
40
TD et TP LO11
UTT 2014/2015
}
return0;
}
#defineRXDP7//RXDP:datapresentenrceptiondansFIFO
//***********************************************************************
//main
//***********************************************************************
intmain(void){
unsignedcharportc,portd;
usart_init();
while(1){
portc=PINC;
if(portc&(1<<RXDP)){//sidatapresent
portd=PIND;
usart_send(portd);
}
}
return0;
}
e(1)
e(0)
parit
b7
b6
b5
b4
b3
b2
b1
b0
caractre
'0'
'1'
'2'
'3'
'4'
'5'
'6'
'7'
'8'
68/94
TD et TP LO11
UTT 2014/2015
'9'
'A'
'B'
'C'
'D'
'E'
'F'
69/94
TD et TP LO11
UTT 2014/2015
INFO
xn
x0
y0
z0
CORDIC
yn
zn
Figure111:Symboledel'lmentCORDIC
Les diffrentes itrations de lalgorithme sont donnes par :
x i+1=x i iy ii
yi +1= y i + x
i ii
zi +1=z i ii
{
o
i =1
1. crire les deux premires quations sous la forme matricielle en calculant la matrice
Ci :
v i +1=Civ i avec v i=( x i , y i )T et v i +1=(x i +1 , y i+1 )T
La matrice Ci peut galement s'crire : Ci = Ki . Ri.
Ki est un scalaire correspondant un facteur dchelle et Ri est une matrice de rotation
de mme dimension que Ci et pouvant scrire :
Ri=
cos( i) i sin(i )
i sin(i )
cos( i)
70/94
TD et TP LO11
UTT 2014/2015
3. Soit v0 la valeur initiale de vi, exprimer le vecteur vi en fonction de v0 et de Ci-1, Ci2, ... .
4. Exprimer vn (vecteur vi aprs n itrations) en fonction de v0, Kn-1, Kn-2, ... et Rn-1, Rn2, ... .
Nous considrons i = 2-i avec i=0,1,2,...,n.
5. Calculer i pour i=0, 1,2,...,10 (en radian) avec OpenOffice :
A
alpha_i
0,785
"=ATAN(PUISSANCE(2;-A2))"
le cas particulier o le sens de rotation est positif ( i = 1), calculer la valeur de pour
n=20. (Avec OpenOffice : "=somme(B2:B22)")
Le nombre K est appel facteur dchelle. Il a pour expression :
n
K=K 0K 1K 2...K n= K i
i=0
7. Exprimer Ki en fonction de i.
8. Nous considrons i = 2-i. Calculer K pour n=20 l'aide d'OpenOffice et comparer la
valeur 1,646760245 gnralement prise pour les calculs (d'inverse 0,60725294 arrondi
0,6073).
A
delta_i
0,500
0,25
alpha_i
K_i
<--"=PUISSANCE(2;-A2)"
>
<-- "=1/cos(C2)"
"=ATAN(B3)"--
Le produit demand est ralis avec "=produit(D2:D22)" dans une cellule en dehors du
tableau.
La troisime quation de lalgorithme de CORDIC est gale : z i+1=z i i i
9. Exprimer zn, valeur de z aprs n itrations, en fonction de z0, i , i et n.
71/94
TD et TP LO11
UTT 2014/2015
angle= k k
k=0
i +1=+1lorsque angle< z 0
i +1=1lorsque angle> z 0 (6)
10. On prolonge la partie tableur de la question 8 pour grer toute la partie angle de la
question 9 dans les colonnes E, F et G.
A
z_i
1,047
"=E2C2*G2"
angle_i
sigma_i
<--"=PI()/3"
<--"=SI(F2<$E$2;1;-1)"
"=F2+G2*C2"->
z_i
1,047
"=E2C2*G2"
x_i
y_i
<--"=PI()/3"
"=H2-G2*I2*B2"-->
0
<-- "=I2+H2*G2*B2"
72/94
TD et TP LO11
UTT 2014/2015
Remarque : pour vos essais, n'oubliez pas que l'algorithme CORDIC fonctionne entre
[ , ]
2 2
hello.elf hello.bin
La dernire ligne gnre un fichier binaire dont la taille donne la taille de la mmoire
Programme utilise (8 ko pour l'ATTiny861). Tout ajout dans le programme d'origine ne
tiendra pas dans l'ATTiny861 !!!
2) Nous dsirons modifier le programme prcdent pour qu'il fonctionne sans les
librairies de calcul en double (librairie mathmatique qu'utilisent pow(2,-i) et
atan(Pow2)) .
La technique habituelle pour faire cela est de choisir un format virgule fixe en lieu et
place des variables de type "double". Puisque les nombres sont positifs ou ngatifs on
utilisera, au choix, des "int" ou des "int16_t". Nous allons utiliser un format Q3.13 qui
veut dire que trois bits de poids forts sont la partie entire et les treize bits restants sont
la partie fractionnaire. Voici un rsum du codage utilis avec les poids correspondants :
b15 b14 b13 b12 b11 b10 b9
b8
b7
b6
b5
b4
b3
2-5
2-6
2-7
2-8
2-9
1 2-1
2-2
2-3
2-4
b2
b1
b0
S est le signe et la partie entire possde donc 2 bits, l'ensemble est cod en
complment deux.
Calculer les valeurs de 1, 0.5 et -0.25 en format Q3.13. Montrer que les multiplications
par i = 2-i se font par de simples dcalages mais qui ne sont pas identiques suivant que
les nombres sont positifs ou ngatifs.
3) (Avec gcc sous Linux) Remplacer tous les types "double" en type "float" dans le
programme de Wikipdia. La raison est que les sous programmes donns ci-dessous
manipulent des "float".
Calculer les valeurs des atan(2-i) et les convertir (pour un usage ultrieur en Q3.13)
l'aide des sous-programmes de conversion tout faits :
1
2
3
4
5
6
7
floatHexQ3_13ToFloat(intval){//conversionQ3.13versfloat
floattemp;
inti_temp;
chari;
if(val<0)i_temp=val;elsei_temp=val;
temp=((i_temp&0x6000)>>13);
for(i=0;i<13;i++)
73/94
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
TD et TP LO11
UTT 2014/2015
if(i_temp&(1<<i))temp+=pow(2,(i13));
if(val<0)returntemp;elsereturntemp;
}
intfloat2HexQ3_13(floatval){//conversionfloatversQ3.13
inttemp;
chari;
floatf_temp;
if(val<0)f_temp=val;elsef_temp=val;
temp=((int)floor(f_temp)<<13);
f_temp=f_tempfloor(f_temp);
for(i=0;i<13;i++){
temp|=((int)floor(2*f_temp)<<(12i));
f_temp=2*f_tempfloor(2*f_temp);
}
if(val<0)returntemp;elsereturntemp;
}
Ce travail se fait sous Linux bien sr. Expliquer alors pourquoi un tableau de 14 valeurs
suffit. Pour ce travail vous avez le droit d'utiliser la librairie mathmatique en float (ou en
double).
4) (avec gcc sous Linux) En remarquant que le calcul de atan peut tre remplac par un
tableau compos des valeurs de la question prcdente, et que les multiplications
peuvent tre remplaces par des dcalages, on vous demande d'crire le programme
complet de calcul avec le tableau et les itrations.
Indication : calcul rcursif CORDIC sans aucune multiplication !
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for(i=0;i<nb_iter;i++){
//Sibeta<0rotationdanslesenstrigo
if(beta<0){
x_Nouveau=x+(y>>i);
y=x>>i;
beta+=atantb[i];
}
//sinondansl'autresens
else{
x_Nouveau=x(y>>i);
y+=(x>>i);
beta=atantb[i];
}
x=x_Nouveau;
}
74/94
TD et TP LO11
UTT 2014/2015
puisqu'on n'a plus d'cran ni de clavier. Vous allez maintenant utiliser GTKTerm, c'est
dire que vos entres sorties seront faites par la liaison srie.
1) Dans un premier temps, on vous demande d'utiliser votre programme sans les
fonctions de conversion : vous fournirez vos donnes directement en dur dans votre
programme. Aprs calcul, vous comparerez aux valeurs pr-calcules correspondantes
sous Linux et envoyez une chaine de russite et/ou une chane d'chec l'aide des
fonctions ci-dessous GTKTerm.
Indications :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//************************************************************************
//functionuart_init()
//purpose:putcharacterinfirstrs232PORT
//arguments:
//correspondingcharacter
//return:
//note:38400,8,n,2hardcoded:transmissionandreception
//************************************************************************
voidusart_init(void){
UCSRB=(1<<TXEN)|((1<<RXEN));//transmissionetreception
}
//************************************************************************
//functionuart_send()
//purpose:putcharacterinfirstrs232PORT
//arguments:
//correspondingcharacter
//return:
//note:38400,8,n,2hardcoded
//************************************************************************
voidusart_send(unsignedcharch){
while(!(UCSRA&(1<<UDRE)));
UDR=ch;
}
//************************************************************************
//functionuart_receive()
//purpose:readcharacterinsecondrs232PORT
//arguments:
//correspondingcharacter
//return:nonblockingsubreturn1ifnodatapresentelsereturnchar
//note:38400,8,n,2hardcoded,nonblockingsubreturn0ifnodatapresent
//************************************************************************
charusart_receive(void){
if(UCSRA&(1<<RXC))//attentetantqueDataPresentenrception
returnUDR;
elsereturn0;
}
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
TD et TP LO11
UTT 2014/2015
str[0] = '-';
valQ3_13 = -valQ3_13;
} else
str[0] = '+';
digit = valQ3_13 >> 13;
str[1]= digit + '0';
str[2]= '.';
valQ3_13 &= 0x1FFF; // on retire les 3 bits de poids fort
valQ3_13 = valQ3_13 * 5; //*5 pour tenir dans 16 bits
valQ3_13b = valQ3_13;
valQ3_13b >>= 12; // on ne garde que les 4 bits de poids fort
str[3] = valQ3_13b +'0';
valQ3_13 &= 0x0FFF; // on retire les 4 bits de poids fort
valQ3_13 = valQ3_13 * 10; //enfin le * 10
valQ3_13b = valQ3_13;
valQ3_13b >>= 12; // on ne garde que les 4 bits de poids fort
str[4] = valQ3_13b +'0';
valQ3_13 &= 0x0FFF; // on retire les 4 bits de poids fort
valQ3_13 = valQ3_13 * 10; //enfin le * 10
valQ3_13b = valQ3_13;
valQ3_13b >>= 12; // on ne garde que les 4 bits de poids fort
str[5] = valQ3_13b +'0';
valQ3_13 &= 0x0FFF; // on retire les 4 bits de poids fort
valQ3_13 = valQ3_13 * 10; //enfin le * 10
valQ3_13b = valQ3_13;
valQ3_13b >>= 12; // on ne garde que les 4 bits de poids fort
str[6] = valQ3_13b +'0';
str[7]=0;
}
Ceci rendra votre programme plus convivial. Quelle est la nouvelle taille du programme ?
3) Raliser un sous-programme de conversion d'une chane en provenance de GTKTerm
en format Q3.13. Cela permettra d'envoyer des angles pour calculer leurs cosinus et
sinus. Pour simplifier le problme, on adoptera un format fixe : un signe, un chiffre un
point et quatre chiffres. Par exemple "+0.7853" et "-1.0472" seront des chaines valides.
ATTENTION : vitez d'utiliser float2HexQ3_13 dans l'ATMega8
qui ne fonctionne pas ! Mais nous avons ajout
float2HexQ3_13_AVR dans les ressources.
TD et TP LO11
UTT 2014/2015
Exercice 3
1) Complter toutes les valeurs numriques manquantes du cur cordic fourni ( partir
des calculs de l'exercice 1).
2) Ajouter la gestion de l'entre "ena" : cette entre est dclare dans l'entit mais elle
n'est pas utilise dans le cur.
3) Interfacer le cur VHDL CORDIC pour en faire un priphrique de votre AVR en
suivant les schmas ci-dessous. Vous devez avoir l'esprit que ce cur fonctionne tant
que son entre "ena" est un. Ceci montre que ce cur n'est pas bien adapt notre
travail : il est plutt utile pour un ensemble de donnes qui lui arrive et ralise alors un
calcul pilpelin : calcul en mode flot de donnes (stream processing). Cependant, tant
que "ena est laisse 1 assez longtemps et que les valeurs en entre ne changent pas,
il est possible de l'utiliser tel quel. Pour dire les choses autrement, il serait prfrable
d'avoir un cur avec une entre "start" et une sortie "done" plutt qu'une seule entre
"ena" ! Ce serait plus l'esprit de l'interfaage avec un processeur, le "done" tant projet
en bit interne. C'est ce que l'on a utilis en TP 10 pour le clavier.
En ce qui concerne le rsultat du cur CORDIC, il sera interfac comme quatre PORTs
d'entres, deux pour le sinus et deux pour le cosinus. Notez dans le dessin qui est poids
faible (LSB) et qui est poids fort (MSB).
PORTD sera rserv faire partir de calcul l'aide de l'entre "ena" du cur CORDIC.
Cette gestion mriterait d'tre amliore.
Les (-) devant les entres/sorties veulent dire que celles-ci peuvent tre supprimes car
elles ne sont plus utilises. Ces suppressions sont optionnelles. Les (+) devant les
entres/sorties veulent dire que celles-ci doivent tre ajoutes (aucune ici).
Vous devez savoir que le processeur ATMega8 ne possde pas de PORTA que l'on a
utilis pour le poids faible du sinus. Son utilisation ncessite donc de complter le fichier
avr/io.h. Pour ne pas modifier ce fichier vous utiliserez plutt, en dbut de votre
programme :
1
2
3
4
/*PortA*/
#definePINA_SFR_IO8(0x19)
//#defineDDRA_SFR_IO8(0x1A)
//#definePORTA_SFR_IO8(0x1B)
sans vous inquiter du dcalage de 0x20 qu'il y a entre les adresses dans nos dessins et
l'adresse fournie ici.
4) Essayer ce cur matriel en utilisant la liaison srie pour visualiser vos rsultats.
Puis ralisez la question 3 de l'exercice 2 pour avoir un moyen de fournir des angles
avec GTKTerm.
5) Cette question sera ralise en lieu et place de l'exercice suivant si vous ne disposez
pas assez de temps pour le raliser (minimum 1h30). Ajouter un compteur sur 4 bits qui
se dclenche avec "ena" et ralise un signal "done" dans un bit du processeur.
Exercice 4 Transformer le cur pipeline en priphrique
Le cur pipeline du CORDIC que nous avons donn plus haut est assez mal adapt la
notion de priphrique. Il est en effet trop indpendant du processeur.
77/94
TD et TP LO11
UTT 2014/2015
Ce qui nous dplat dans cette faon de faire est l'attente par perte de temps. A ce
stade, peu d'amlioration par rapport au cur d'origine, sauf la possibilit de l'arrter.
Nous allons corriger cela mais avant, nous vous demandons de raliser cette tape et de
la tester.
2) Ajouter une dtection de la fin de calcul
Un bit de sortie sera prvu pour dtecter la terminaison du calcul. Ce travail n'est pas
difficile faire. Il s'agit d'ajouter un compteur dans CORDIC sur 4 bits qui s'incrmente
aussi avec "ena" (et l'horloge bien sr). Quand le compteur est une certaine valeur (14
pour nous) et bien on positionne un bit 1 (et l'on peut automatiquement positionner
"ena" 0).
L'utilisation d'un tel cur consistera alors :
Indication :
La gestion du "done" se fait en deux tapes :
1) on ajoute dans CORDIC (fichier cordic2.vhd) un compteur qui compte de 0 14
quand ena=1, qui s'arrte 14 et qui se remet 0 quand "ena" repasse 0.
Un processus combinatoire positionne la sortie "done" quand le compteur vaut 14.
2) Il faut maintenant grer le bit done dans le process iord (donc dans le fichier io.vhd)
Ceci implique que le processeur ne pourra pas changer ce bit, c'est le matriel qui le
fera.
Remarque
La faon d'organiser tout ce fonctionnement peut se faire avec quelques petites
variations (donnes juste titre indicatif) :
78/94
TD et TP LO11
UTT 2014/2015
le deuxime choix peut mme amener retirer le bit fin de calcul : c'est "ena" qui
sert tout : on le positionne '1' et on attend qu'il repasse 0
31
S
23 22
Voici comment les choses se font sous Linux : on remarquera l'absence de multiplication
et de calcul flottant :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
floatHexQ3_13ToFloat2(intval){
float*temp;
inti_temp,f_temp;
unsignedcharexposant=129;
signedchari;
if(val<0)i_temp=val;elsei_temp=val;
for(i=15;i>=0;i){
if(i_temp&(1<<i)){
//oneffacele'1'trouv:
i_temp=i_temp&~(1<<i);
break;//onsortdelaboucle
}
exposant;
}
f_temp=exposant;
f_temp<<=23;
f_temp=f_temp|(i_temp<<(23i));
//cetteaffectationdepointeurprovoqueraunwarning!:
temp=&f_temp;
79/94
20
21
TD et TP LO11
UTT 2014/2015
if(val<0)return(*temp);elsereturn*temp;
}
L_RD_FIFO<=I_RD_IOwhen(I_ADR_IO=X"39")else'0';readPINA
avr_fpga_spartan3.vhd
io.vhd
I_CLK_50
I_CLR
I_RX
I_SWITCH[7:0]
I_CLK
I_CLR
I_ADR_IO[7:0]
I_DIN[7:0]
I_SWITCH[7:0]
I_RD_IO
I_RX
I_WE_IO
Q_INTVEC[5:0]
Q_TX
Q_7_SEGMENT[6:0]
Q_LEDS[7:0]
Q_AN[3:0]
Q_TX
iord: process(I_ADR_IO,...
PINA (0x39)
FIFO
I_ADR_IO[7:0]
80/94
Q_DOUT[7:0]
TD et TP LO11
UTT 2014/2015
81/94
TD et TP LO11
UTT 2014/2015
I. Notions mathmatiques
Le corps de Galois GF(2)
Le corps de Galois GF(2) comporte deux lments qui seront nots '0' et '1'. Il est muni
de deux oprations :
- addition + qui un OU exclusif que l'on notera abusivement par +
- multiplication note . qui est un ET logique
Ces deux oprateurs ont toutes les proprits de l'arithmtique : commutativit,
associativit lment neutre et, de plus, la multiplication est distributive par rapport
l'addition.
Polynmes sur GF(2)
Le Corps de Galois GF(2) permet de dfinir des polynmes coefficients dans GF(2). Par
exemple, le polynme du cinquime degr a5 . x + a4 . x + a3 . x 3+ a2 . x +a1 . x +a 0 aura tous
ses coefficients ai dans GF(2) et sera reprsent comme le contenu d'un registre ayant
des '0' et '1' la place des ai.
b5 b4 b3 b2 b1 b0
a5 a4 a3 a2 a1 a0
Avec cette convention, tout polynme peut tre reprsent par une valeur binaire ou
hexadcimale.
Le contrle de redondance cyclique
En gnral le calcul d'un code CRC se fait par division euclidienne dans le corps GF(2).
Ainsi l'opration ralise peut s'crire :
M (x)x n=Q (x)G( x )+ R ( x)
o M(x) est le message envoyer, Q(x) le quotient (qui ne nous intresse pas) G(x) est
le polynme gnrateur (forcment de degr n) connu par lmetteur et le rcepteur et
R(x) est le reste qui sera le contrle de redondance cyclique. La multiplication par xn qui
apparat dans la formule dnote qu'il faut ajouter n '0' sur les poids faibles avant de
commencer les oprations. Lors de l'envoi du message ces '0' seront remplacs par R(x).
TD et TP LO11
UTT 2014/2015
intmain(void){
unsignedcharchaine[20],i;
crccrc_chaine;
usart_init();
while(1){
83/94
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
TD et TP LO11
UTT 2014/2015
i=0;
do{
chaine[i]=usart_receive();
usart_send(chaine[i]);
i++;
}while(chaine[i1]!=0x0D);
//usart_send(ch);
//ajoutdes16bits0:
chaine[i1]=0x00;
chaine[i]=0x00;
crc_chaine=crcSlow(chaine,i+1);
usart_puts_hexa(crc_chaine);
_delay_ms(500);
}
return0;
}
Il vous faudra naturellement ajouter les sous-programmes ncessaires qui sont tous
disponibles dans les ressources.
La compilation pourra se faire avec un script du genre :
#!/bin/bash
export PATH=$PATH:/usr/local/avr/bin:~/XILINX/Xilinx/11.1/ISE/bin/lin/
avr-gcc -g -mmcu=attiny861 -Wall -Os -c tp12exo1.c
avr-gcc -g -mmcu=attiny861 -Wall -Os -c crc.c
avr-gcc -g -mmcu=attiny861 -o tp12exo1.elf -Wl,-Map,tp12exo1.map tp12exo1.o crc.o
cp ../microcontroleur.bit .
data2mem -bm attiny861.bmm -bd tp12exo1.elf -bt microcontroleur.bit -o uh
microcontroleur
qui vous montre comment compiler quand il y a plusieurs fichiers (tp12exo1.c + crc.c).
Pour contourner le problme de la question 2), nous allons raliser un calcul du CRC
matriel.
TD et TP LO11
UTT 2014/2015
microcontroleur.vhd
clk
rst
sw[7:0]
in_PINB[7:0]
iowr: process(I_CLK)
PORTA
IO_DWr[7:0]
PORTB
ADCH
IO_A[5:0]
rst=s_ADCH(7) crc_gen
reset
soc
'0'
Q
Aff7segs[7:0]
s_ADCH
ADCL
8
data[7:0]
clk
D
leds[7:0]
crc_valid
data_valid_d data_valid
s_ADCH(6) eoc
open
clk
s_data_valid <= IO_wr when (IO_A = ADCL) else '0';
Remarque 2 : la bascule D peut tre ralise dans un process et non avec un composant.
Remarque 3 : On garde toute la gestion de la RS232 qui n'est pas prsente ici.
Voici maintenant la partie qui gre l'entre du rsultat dans les deux registres ADCL et
ADCH.
85/94
TD et TP LO11
microcontroleur.vhd
clk
rst
sw[7:0]
in_PINB[7:0]
UTT 2014/2015
iord: process(CLK)
PINA
IO_Drd[7:0]
PINB
ADCH
IO_A[5:0]
rst=s_ADCH(7) crc_gen
reset
soc
'0'
data[7:0]
crc[15:0]
clk
D
ADCL
crc_valid
data_valid_d data_valid
s_ADCH(6) eoc
open
clk
s_data_valid <= IO_wr when (IO_A = ADCL) else '0';
86/94
TD et TP LO11
b9 b8 b7 ........................ b0
TC1H
TCNT1
b7
b6
b5
b4
b3
CS13
b2
b1 CS12
b0 CS11
max(8 bits)
b7
b6
b5
b4
b3
b2
b1
b0
TCCR1B
UTT 2014/2015
MCU
Clock
0,1,2,4,8,16,32,64
CS10
TOV1
TIFR
Indication 2 :
On prendra soin de dfinir les deux constantes TCNT1 et TCCR1B. On ralisera ensuite
le clbre :
s_wr_TCNT1 <= IO_wr when IO_A = TCNT1 else '0';
TD et TP LO11
UTT 2014/2015
else '0';
Vous compltez correctement les deux process iowr et iord et c'est tout.
Indication 3 :
Le programme d'essai sera du genre :
int main (void) {
unsigned char chaine[20],i,j,ta;
unsigned int temps;
crc crc_chaine;
usart_init();
// configuration du timer 1
TCCR1B = 0x07; // demarrage avec prescaler 64
while(1) {
i = 0;
usart_puts("Entrez une chaine");
do {
chaine[i] = usart_receive();
usart_send(chaine[i]);
i++;
} while (chaine[i-1] != 0x0D);
// ajout des 16 bits 0 :
chaine[i-1] = 0x00;
chaine[i] = 0x00;
TCNT1 = 0;
crc_chaine = crcSlow(chaine, i+1);
ta=TCNT1;
usart_puts_hexa(crc_chaine); usart_puts(" temp(soft)=");usart_puts_hexa(ta);
// preparation matrielle
TCNT1 = 0;
88/94
TD et TP LO11
UTT 2014/2015
}
crc_chaine = ADCH;
crc_chaine <<= 8;
crc_chaine += ADCL;
ta=TCNT1;
usart_puts(" : ");usart_puts_hexa(crc_chaine);
usart_puts(" temp(hard)=");usart_puts_hexa(temps);
usart_send(10);usart_send(13);
_delay_ms(500); // on est pas press
}
return 0;
}
o l'on voit que l'on a pris le prscaler division par 64... et qui me donne 0x40 et 0x0C
comme temps de ralisation.
Exercice 3
Nous avons examin en question 2 de l'exercice 1 les difficults qu'il y a pour implanter
logiciellement crcFast(). Nous allons chercher rsoudre ce problme de deux manires
diffrentes.
1-a) En profitant de la prsence de deux RAMB16S4 (soit 4 ko), on vous demande de
modifier dm.vhd pour rendre les 4ko disponibles pour le processeur.
1-b) Portez la primitive crcInit() pour cette nouvelle configuration et testez son bon
fonctionnement en utilisant crtFast().
Indication : L'utilisation de la mmoire RAM non prvue par le compilateur ncessite
une bonne comprhension du compilateur et en particulier des pointeurs. Ceci se fait de
la manire suivante :
- dclaration d'un pointeur : unsigned char *memoirebonus;
- initialisation de l'adresse du pointeur : memoirebonus =0x260; //1octet dispo
- affectation d'une valeur : *memoirebonus=65;
2-a) Raliser matriellement le prcalcul de crcFast() de la ressource crc.c pour une
utilisation sans pointeur.
2-b) Raliser le programme et tester.
89/94
TD et TP LO11
UTT 2014/2015
INFO
Dans le TP prcdant, nous avons tudi l'algorithme CORDIC avec l'AVR. Dans ce
chapitre, nous allons continuer dans deux directions :
Pour viter l'apprentissage d'un nouvel IDE, nous allons utiliser Energia qui est un IDE
Arduino-like donc trs facile utiliser. Le langage est du C (plus exactement C++) mais
sans main() . Celui-ci est remplacer par un void setup() et un void loop()
y= hix i
i= 0
90/94
TD et TP LO11
UTT 2014/2015
Travail faire
1) On vous demande d'crire une nouvelle version de CORDIC qui utilise le multiplieur
16x16 pour faire les dcalages lors du calcul CORDIC. Utilisez la documentation du
multiplieur ci-dessous. Mesurer le nouveau temps d'excution. Conclusion.
{
o
x i+1=x i iy ii
yi +1= y i + x
i ii
zi +1=z i ii
i =1
91/94
TD et TP LO11
UTT 2014/2015
Travail faire
92/94
TD et TP LO11
UTT 2014/2015
1) On vous demande simple ment d'interfacer l'ensemble matriel cur SPI et cur
CORDIC (tous les deux fournis) pour en faire un priphrique matriel.
2) Une fois ce travail ralis, concevoir le logiciel sur le MSP430 qui donne des angles
au priphrique matriel et rcupre les rsultats. La mesure du temps d'excution peut
tre faite titre de comparaison mais on sait d'avance qu'elle sera moins bonne que les
ralisation prcdentes cause des changes SPI.
93/94
TD et TP LO11
UTT 2014/2015
INFO
Il y avait seulement 12 TPs cette anne 2013/2014. Ce TP n'a donc pas t rdig. Lisez
le WIKI correspondant :
https://fr.wikiversity.org/wiki/Very_High_Speed_Integrated_Circuit_Hardware_Description_
Language/Interfaces_VGA_et_PS2
Travail raliser
AVR_FPGA
I_CLK_50
I_CLR
I_RX
I_SWITCH[9:0]
io2
I_CLK
Q_7_SEGMENT[6:0]
+ I_CLK_50
Q_DOUT[7:0]
I_CLR
Q_INTVEC[5:0]
I_ADR_IO[7:0]
Q_LEDS[7:0]
I_DIN[7:0]
Q_AN[3:0]
I_SWITCH[7:0]
Q_TX
I_RD_IO
+ hsynch
I_RX
+ vsynch
I_WE_IO VGATop
+ red
+ green
CLK_50
+ blue
x_rect[9:0]
hsynch
y_rect[9:0]
vsynch
y_raquG[7:0]
red
y_raquD[7:0]
green
scoreG[7:0]
blue
ligne1[7:0]
ligne2[7:0]
94/94
Q_7_SEGMENT[6:0]
Q_LEDS[7:0]
Q_AN[3:0]
Q_TX
+ hsynch
+ vsynch
+ red
+ green
+ blue