Sie sind auf Seite 1von 16

Brion Claire Groupe A11

Chauvin Caroline

Projet VHDL :
Affichage sur écran VGA

ENSEIRB 2004
Sommaire

I- Création des trames....................................................................................... - 4 -

II- Affichage de la palette de couleur............................................................... - 7 -

III- Affichage des premiers caractères ............................................................. - 8 -

IV- Affichage d’un message .......................................................................... - 10 -

V- Personnalisation du projet......................................................................... - 12 -

VI- Synthèse ................................................................................................... - 15 -

-2-
Introduction :

Le but de ce projet était d’écrire, au moyen du VHDL, une application d’affichage sur
écran et de l’implanter sur un circuit interface VGA.
Le projet est axé autour de cinq différentes étapes :
- Premièrement : compléter le fichier « interface_vga.vhd » de façon à envoyer à
l’écran les trames nécessaires de synchronisations horizontales et verticales, à
l’affichage des données commandées par l’entrée « RGB ».
- Deuxièmement : afficher une palette de couleur, en insérant le fichier « palette.vhd »
au programme initial.
- Troisièmement : afficher les 40 premiers caractères contenus dans « fonts.vhd », en
gérant leur couleur et celle du fond.
- Quatrièmement : faire apparaître le texte souhaité à un endroit choisit.
- Enfin, le dernier test est une amélioration, ou personnalisation, de notre affichage.

Avant le troisième test, nous n’avions vérifié notre programme que par la simulation. Pour
cela, on simulait pendant 20ms avec la variable d’initialisation à ‘1’ et l’horloge à une
fréquence de 40ns et de rapport cyclique ½.

Par la suite, nous avons effectué un test réel avec implantation du circuit. Il a fallut
corriger un peu notre programme, le personnaliser avant d’obtenir notre projet final appelé :
« Poppins ».

-3-
I- Création des trames

Le signal vidéo utilisé dans le cadre de notre projet est constitué de cinq signaux : trois
analogiques pour chacune des couleurs rouge, vert, bleu et deux signaux logiques pour les
synchronisations horizontale et verticale. La première étape consistait à créer ces signaux
notés respectivement « red », « green », « blue », « vga_hs » et « vga_vs ». Il fallait
également définir la fréquence de l’horloge, « video_clk », et « blank_n » qui correspond à la
validation des pixels (c'est-à-dire qu’on n’affiche pas de pixels pendant un retour à la ligne et
un changement d’écran).
Le circuit Xilinx fournit une fréquence de 24Mhz, on utilise donc celle-ci, cependant pour
simplification les calculs sont fait à 25Mhz. De plus, les synchros et la validation des pixels
sont définies comme suit :

1
vga_hs
0 Synchro horizontale
751 656 Pixel
1
blankh
0 Validation des pixels
0 ou 794 640 Pixel horizontaux

1
vga_vs
0 Synchro verticale
493 491 Ligne
1 Validation des pixels
blankv
0 verticaux
0 ou 525 480 Ligne

Les signaux « blankh » et « blankv » sont définis de telle sorte que « blank_n = blankh ou
blankv ». Les signaux « red », « green » et « blue » sont définis à partir du signal d’entrée
« RGB » : « RGB » est un vecteur de 24 booléens, « red » est définit par les huit premiers,
« green » par les huit suivants et « blue » par les huit derniers. Les signaux « m1 », « m2 »,
« sync_n » et « sync_t » sont constants et définis réciproquement à ‘0’, ‘0’, ‘1’ et ‘0’. Enfin,
les signaux de sortie « ligne_pix » et « colonne_pix » sont réciproquement égaux aux
variables de comptage de ligne et de colonne.
Nous obtenons donc le fichier « interface_vga.vhd » suivant :

-4-
ENTITY interface_vga IS
PORT(
init : IN std_ulogic; -- reset de l'interface
clk_24Mhz : IN std_ulogic; -- horloge pixel
rgb : IN std_logic_vector(23 DOWNTO 0); -- 3 couleurs
red : OUT std_logic_vector(7 DOWNTO 0); -- entree 1er dac
green : OUT std_logic_vector(7 DOWNTO 0); -- entree 2eme dac
blue : OUT std_logic_vector(7 DOWNTO 0); -- entree 3eme dac
ligne_pix : OUT std_logic_vector(9 DOWNTO 0); -- compteur lignes pixels
colonne_pix : OUT std_logic_vector(9 DOWNTO 0); -- compteur colonnes
pixels
m1, m2 : OUT std_ulogic; -- mode select dac
blank_n : OUT std_ulogic; -- commande DAC
sync_n : OUT std_ulogic; -- commande DAC
sync_t : OUT std_ulogic; -- commande DAC
video_clk : OUT std_ulogic; -- commande DAC
vga_vs : OUT std_ulogic; -- sur connecteur VGA
vga_hs : OUT std_ulogic -- sur connecteur VGA
);
END interface_vga;

ARCHITECTURE perso OF interface_vga IS

SIGNAL blankh, blankv : std_ulogic;

BEGIN -- perso

video_clk <= clk_24Mhz ;


m1 <= '0';
m2 <= '0';
sync_n <= '1';
sync_t <= '0';
red <= rgb(23 DOWNTO 16);
green <= rgb(15 DOWNTO 8);
blue <= rgb(7 DOWNTO 0);

un_seul : PROCESS
VARIABLE x,y : natural := 0; --initialisation des compteurs

BEGIN
WAIT UNTIL rising_edge(clk_24Mhz); --synchronisation sur l’horloge

IF y>=0 AND y<=479 THEN


ligne_pix <= std_logic_vector(to_unsigned(y,10)); --compteur des lignes de pixel
END IF;
IF x>=0 AND x<=639 THEN
colonne_pix <= std_logic_vector(to_unsigned(x,10)); --compteur des colonnes
END IF;

IF init ='0' THEN --signal d’initialisation


x := 0;
y := 0;
END IF;

IF x>=640 AND x<794 THEN


blankh <= '0'; --fin de validation du pixel
END IF;
IF x>=0 AND x<640 THEN
blankh <= '1'; --validation du pixel
END IF;
IF x>=0 AND x<656 THEN --synchro horizontale
vga_hs <= '1';
END IF;
IF x>=656 AND x<751 THEN
vga_hs <= '0';
END IF;
IF x>=751 AND x<794 THEN
vga_hs <= '1';
END IF;

IF x = 793 THEN
x := 0; --début de ligne
y := y+1; --fin de ligne : passage a la ligne suivante
ELSE
x := x+1; --passage au pixel suivant
END IF;

IF y>=0 AND y<480 THEN --validation de


la ligne
blankv <= '1';
END IF;
IF y>=480 AND y<525 THEN
blankv <= '0';
END IF;
IF y>=0 AND y<491 THEN --synchro verticale
vga_vs <= '1';
END IF;
IF y>=491 AND y<493 THEN
vga_vs <= '0';
END IF;
IF y>=493 AND y<525 THEN
vga_vs <= '1';
END IF;
IF y = 524 THEN
y := 0; --ecran suivant
END IF;

blank_n <= blankv AND blankh; --définition du blank_n

END process;
END perso;

Nous avons tout d’abord testé ce fichier seul, en laissant « RGB » de côté, le but étant
juste de vérifier que les trames émises étaient celles attendues. Nous avons rajouté un signal
« init » d’initialisation qui doit être à un pour que l’envoi des trames commence. En réglant
l’horloge à 24Mhz, on observe avec le logiciel de simulation des signaux correspondant à
notre attente.

Synchro horizontale

Synchro verticale

Nous en sommes restées là pour cette étape, mais par la suite nous avons découvert que ce
fichier contenait une erreur. En fait, on réinitialisait mal les variables de comptages des pixels
et des colonnes, si bien qu’elles ne valaient jamais ‘0’, ce qui entraînait un décalage, visible
lorsqu’on affichait des lettres à l’étape trois.

-6-
II- Affichage de la palette de couleur

La seconde étape permettait de vérifier que les trames créées auparavant étaient correctes.
Pou cela, on utilise le fichier déjà créé « palette.vhd ». Ce programme prend en entrée la
couleur désirée pour l’affichage, sous la forme d’un vecteur de huit booléens, et redonne un
vecteur de 24 booléens, correspondant à l’entrée « RGB » de « interface_vga.vhd ». Pour
avoir toutes les couleurs de la palette, il suffit ensuite de reboucler le signal de « ligne_pix »
provenant de « interface_vga.vhd » sur l’entrée de « palette.vhd ».
Ces liaisons entre fichiers s’effectuent sur un « bloc diagramme ». On y rajoute le fichier,
également déjà entièrement créé, « moniteur_vga.vhd ». Ce programme permet également de
visualiser le résultat qu’on obtiendrait sur l’écran, grâce au logiciel xview.
Le bloc diagramme à l’allure suivante :

Ce bloc diagramme nous a donné du premier coup l’écran attendu, on est donc passé
directement à la suite.

-7-
III- Affichage des premiers caractères

Le fichier « fonts.vhd », fournit l’ensemble des caractères les plus usités, codés sur une
matrice de 8 par 8 pixels et repéré par une adresse fournie. Ce fichier, qui prend en entrée
l’adresse du caractère choisit et la position dans l’écran, donne un bit à ‘1’ ou à ‘0’. Il faut
alors créer un fichier qui déterminera une couleur différente pour les deux cas. Nous avons
alors créé « couleur_pixel.vhd ».
Ce fichier prend donc en entrée un bit, et selon sa nature, envoi un vecteur différent, de 24
bits, sur l’entrée « rgb » de « interface_vga.vhd » :

ENTITY couleur_pixel IS
PORT (
pixel : IN std_ulogic; --sortie de fonts.vhd
rgb : OUT std_logic_vector(23 DOWNTO 0)); --dans l'ordre r, g, b
END couleur_pixel;

ARCHITECTURE pixels OF couleur_pixel IS

BEGIN -- pixels

rgb <=
"000000000000000000000000” WHEN pixel='0'
ELSE "111111111111111111111111";

END pixels;

Tel qu’il est ici, ce fichier permet d’écrire en blanc sur du noir. Pour changer la couleur du
font ou de l’écriture, il suffit de changer des ‘0’ en ‘1’ ou l’inverse dans les vecteurs de 24
bits.
Pour ensuite afficher les premiers caractères, les uns à la suite des autres sur la première
ligne et les suivantes, il faut tout d’abord remarqué, qu’étant donné qu’un caractère est dans
une matrice 8x8, le premier commence au vecteur colonne « 0000000000 », le second au
« 0000001000 », le troisième au « 0000010000 ». Or, si on prend les sept premiers bits de ces
vecteurs, on voit que « 0000000 » donne 0 en binaire, « 0000001 » donne 1 et « 0000010 » 2
(ainsi de suite). Ainsi, l’adresse du caractère à envoyer n’est autre que les sept premiers bits
de « colonne_pix ». Ensuite, pour la place du pixel, il suffit d’envoyer le reste (les trois
derniers bits) à « colonne_font ». De même, « ligne_font » est égal au trois derniers bits de
« ligne_pix ».
En fait, « adresse_caractere » est un vecteur de six bits, on laisse donc tomber le premier
bit de « colonne_pix ».
Pour afficher nos caractères, il faut donc construire le bloc diagramme suivant :

-8-
Le premier test pour ce diagramme, nous a donné l’écran attendu à une particularité près :
les caractères s’affichaient en italique. Nous en avons déduit qu’il y avait un problème au
niveau des trames. En fait, à chaque nouvelle ligne, une colonne disparaissait ! Après quelque
changement, on ne reconnaissait plus les lettres car c’est une ligne à chaque colonne qui
disparaissait ! On a donc repris le fichier ‘interface_vga.vhd » depuis le début pour voir ce qui
n’allait pas.
En fait, lorsqu’on passait à la ligne suivante, on réinitialisait correctement le compteur de
colonne x, mais on l’incrémentait aussitôt, si bien que x ne valait jamais zéro. Une fois
l’erreur corrigée, à l’aide d’une condition en IF, l’écran présentait en effet les 40 premiers
caractères de fonts répétés sur chaque ligne.

Le problème à présent est de contrôlé l’affichage des caractères, c'est-à-dire de n’en


afficher que certain et à l’endroit choisis !

-9-
IV- Affichage d’un message

Tout d’abord, nous avons seulement cherché à n’afficher que les huit premiers caractères
de fonts. Pour cela, il fallait simplement commandé l’intervalle de pixel sur lequel on envoie
les données. On ajoute donc un fichier entre « interface_vga.vhd » et « fonts.vhd » qui décide
d’affecter, ou non, « colonne_pix » et « ligne_pix » à « colonne_font » et « ligne_font ».
L’affectation se fait directement sur le comptage des colonnes et des lignes. L’affichage
des 8 premiers caractères prend 8 lignes et 8x8=64 colonnes. On dit donc que « ligne_font »
reçoit « ligne_pix » et que « colonne_font » reçoit « colonne_pix » uniquement quand, en
décimale, « colonne_pix » est compris entre 0 et 63 et que « ligne_pix » est compris entre 0 et
7.
Le fichier à intercaler doit donc avoir en entrée « colonne_pix », « ligne_pix » et l’horloge
pour synchroniser ce fichier sur le précédent. Il se charge alors d’envoyer l’adresse du
caractère et les données « ligne_font » et « colonne_font ».

Une fois que nous avons compris ceci, nous avons voulu afficher un texte de notre choix
au centre de l’écran. Le texte à afficher était :
« SUPERCALIFRAGILISTIEXPIALIDOUCIOUS »
Il se compose de 34 caractères, il faut donc 34x8=272 colonnes et toujours 8 lignes. Nous
avons donc choisit de l’afficher entre les lignes 239 et 246 et les colonnes 168 et 431, inclus.
Nous avons placé le texte dans un tableau, chaque élément du tableau correspondant à
l’adresse d’une lettre. Il suffit ensuite de prendre chaque élément du tableau dans l’ordre et de
l’envoyer dans l’entrée « adresse_caractere » de « fonts.vhd ». Nous avons donc créé le
fichier (message.vhd) suivant pour réaliser cette opération :

ENTITY messageT IS
PORT(
clk_24Mhz : IN std_ulogic ;
colonne_pix : IN std_logic_vector(9 DOWNTO 0);
ligne_pix : IN std_logic_vector(9 DOWNTO 0);
adresse_caractere : OUT std_logic_vector(5 DOWNTO 0); -- caractere choisi
colonne_font : OUT std_logic_vector(2 DOWNTO 0); -- emplacement
ligne_font : OUT std_logic_vector(2 DOWNTO 0) -- emplacement
);
END messageT;

- 10 -
ARCHITECTURE poppins OF messageT IS
TYPE tableau IS ARRAY (0 TO 33) OF natural;
CONSTANT super : tableau :=
(19,21,16,5,18,3,1,12,9,6,18,1,7,9,12,9,19,20,9,5,24,16,9,1,12,9,4,15,3,9,15,21,19,
33); --tableau contenant le message

BEGIN -- poppins

p3: PROCESS

VARIABLE l,c : natural := 0; --initial


VARIABLE i : std_logic_vector(9 DOWNTO 0); -- variable incrémentale

BEGIN -- PROCESS p3
WAIT UNTIL rising_edge(clk_24Mhz); --synchronisation sur l’horloge

l := to_integer (unsigned(ligne_pix)); --ligne_pix en décimale


c := to_integer (unsigned(colonne_pix)); --colonne_pix en décimale

colonne_font <= "000"; --hors de la zone d’affichage


ligne_font <= "000"; --hors de la zone d’affichage

IF l>=239 AND l<=246 THEN --zone d’affichage


IF c>=168 AND c<=431 THEN
i := std_logic_vector(to_unsigned((c-168),10)); --numéro du caractère
adresse_caractere <= std_logic_vector(to_unsigned(super(to_integer
(unsigned(i(9 DOWNTO 3)))),6));
--envoi de l’adresse correspondant à l’élément i du tableau
colonne_font <= colonne_pix(2 DOWNTO 0);
ligne_font <= ligne_pix(2 DOWNTO 0);
END IF;
END IF;

END PROCESS p3;

END poppins;

Une fois le fichier créé, il faut encore le rajouter dans le bloc diagramme, qui est de plus
en plus important :

- 11 -
V- Personnalisation du projet

Pour personnaliser un peu notre projet, nous avons choisit de commander la taille de notre
texte et sa couleur. Ces deux améliorations avaient l’avantage de se faire assez simplement et
donc assez vite, ce qui était appréciable compte tenu du temps qu’il nous restait.
Nous avons donc modifier d’une part le fichier « couleur_pixel.vhd » et ensuite
« message.vhd » en ajoutant en entrée un interrupteur commandant une variable.

Pour la couleur, nous avons ajouté en entrée de « couleur_pixel.vhd » un interrupteur de 8


bits qui modifie à la fois le font et la couleur de l’affichage. Au début, l’interrupteur ne
commandait que les premiers bits du fond et les derniers de la couleur, mais l’influence de
l’interrupteur n’était pas toujours très visible, nous avons donc au hasard modifié plusieurs
bits en même temps. Nous avons appelé ce nouveau fichier « couleur_pix.vhd » :

ENTITY couleur_pix IS
PORT (
coul : IN std_logic_vector (7 DOWNTO 0); --
interrupteur
pixel : IN std_ulogic; --sortie de fonts.vhd
rgb : OUT std_logic_vector(23 DOWNTO 0)); -- dans l'ordre r, g, b
END couleur_pix;

ARCHITECTURE pixel OF couleur_pix IS

BEGIN -- pixel

rgb <=
coul & "0000" & coul & "0000" WHEN pixel='1'
ELSE "1111" & coul & "1111" & coul;

END pixel;

Pour la taille, on a simplement cherché à doubler la taille des caractères, l’augmentation


étant commandé par un simple interrupteur. Pour cela, il fallait simplement procédé à un
décalage : l’adresse caractère est codée par les six premiers bits de « colonne_pix » (on ne
laisse plus tomber le premier bit) et « colonne_font » et « ligne_font » reçoivent les bits
suivants (on laisse, cette fois, tomber le dernier bit au lieu du premier). On obtient le fichier
« messageT.vhd » suivant :

ENTITY messageT IS
PORT(
clk_24Mhz : IN std_ulogic ; --horloge
double : IN std_ulogic; --interrupteur
colonne_pix : IN std_logic_vector(9 DOWNTO 0);
ligne_pix : IN std_logic_vector(9 DOWNTO 0);
adresse_caractere : OUT std_logic_vector(5 DOWNTO 0); -- caractere choisi
colonne_font : OUT std_logic_vector(2 DOWNTO 0); -- emplacement
ligne_font : OUT std_logic_vector(2 DOWNTO 0) -- emplacement
);
END messageT;

- 12 -
ARCHITECTURE poppins OF messageT IS
TYPE tableau IS ARRAY (0 TO 33) OF natural;
CONSTANT super : tableau :=
(19,21,16,5,18,3,1,12,9,6,18,1,7,9,12,9,19,20,9,5,24,16,9,1,12,9,4,15,3,9,15,21,19,
33); --tableau contenant le message

BEGIN -- poppins

p3: PROCESS

VARIABLE l,c : natural := 0; --initial


VARIABLE i,j : std_logic_vector(9 DOWNTO 0); -- variable incrementale

BEGIN -- PROCESS p3
WAIT UNTIL rising_edge(clk_24Mhz); --synchronisation sur l’horloge

l := to_integer (unsigned(ligne_pix));
c := to_integer (unsigned(colonne_pix));

colonne_font <= "000";


ligne_font <= "000";

IF double='0' THEN --augmentation de


taille
IF l>=239 AND l<=254 THEN
IF c>=48 AND c<=575 THEN
i := std_logic_vector(to_unsigned((c-48),10));
adresse_caractere <=
std_logic_vector(to_unsigned(super(to_integer (unsigned(i(9 DOWNTO
4)))),6));
colonne_font <= colonne_pix(3 DOWNTO 1);
ligne_font <= ligne_pix(3 DOWNTO 1);
END if;
END if;
ELSE
IF l>=239 AND l<=246 THEN
IF c>=168 AND c<=431 THEN
j := std_logic_vector(to_unsigned((c-168),10));
adresse_caractere <= std_logic_vector(to_unsigned(super(to_integer
(unsigned(j(9 DOWNTO 3)))),6));
colonne_font <= colonne_pix(2 DOWNTO 0);
ligne_font <= ligne_pix(2 DOWNTO 0);
END IF;
END IF;
END IF;

END PROCESS p3;

END poppins;

Les changements sont notés en gras.


On obtient au final le schéma bloc suivant :

- 13 -
VI- Synthèse

Une fois le programme fini, on l’a enfin synthétisé sous leonardo, puis implanter dans le
circuit Xilinx. Le rapport fournit par leonardo, nous indique une fréquence maximale de 31,1
Mhz et l’utilisation de 99 bascules.
La fréquence utilisée étant de 24Mhz, la fréquence maximale recueillit nous montre une
bonne performance de notre programme.

Tachons de calculer le nombre théorique de bascules. Les fichiers « fonts.vhd » et


« couleur_pix.vhd » ne contiennent pas de processus, ne sont pas synchronisés donc
n’utilisent pas de bascule. Occupons nous a présent de « interface_vga.vhd ». Ce fichier
nécessite 10 bascules pour « ligne_ pix » et 10 autres pour « colonne_pix » car ce sont des
vecteurs de 10 bits qui sont affectés dans un processus et synchronisés par une horloge. De
même, il faut 31 bascules pour x et autant pour y car ce sont des naturels, affectés dans les
mêmes conditions. Enfin, il faut 1 bascule pour « blankv », « blankh », « blank_n »,
« vga_vs » et « vga_hs », soit 5 nouvelles bascules. Au total, rien que pour
« interface_vga.vhd » il faut :
2x10 + 2x31 +5 = 20 + 62 + 5 = 87 Bascules.
C’est bien le nombre de bascules indiquées par leonardo pour ce fichier.
A présent : « messageT.vhd ». Dans ce fichier, il faut trois bascules pour
« colonne_font », vecteur de trois bits, affecter avec synchronisation d’horloge, et autant pour
« ligne_font ». Il faut également 6 bascules pour « adresse_caractere ». D’autres variables
sont affectées avec la synchronisation, ce sont l, c, i et j mais ces variables ne sont que des
écritures sous d’autres formes de « colonne_pix » et « ligne_pix » (passage de décimale à
vecteur de bits) et donc n’utilise pas de bascule. On a donc au total pour ce fichier :
2x3 + 6 = 12 bascules.
Finalement, notre programmes utilisent donc 87 + 12 = 99 bascules, ce qui vérifient bien
le résultat trouvé par leonardo.
Conclusion :

Nous avons donc testé notre programme en l’implantant sur la carte Xilinx fournit. Le
premier test n’a pas été concluant : seulement une lettre sur trois s’affichaient et
l’initialisation était mal réglée (il fallait maintenir le bouton poussoir appuyé pour voir
l’image apparaître). Pour l’interrupteur, il a suffit de changer un ‘0’ en ‘1’ dans
« interface_vga.vhd ». Les lettres manquantes étaient le résultat d’une mauvaise
synchronisation. En effet, notre « messageT.vhd » était synchronisé sur « ligne_pix », lequel
était synchronisé sur l’horloge, au lieu d’être directement synchronisé sur l’horloge.
On a rencontré un autre problème, mais plus tôt en simulation : les lettres
n’apparaissaient pas correctement, elles étaient coupées en deux voire en quatre ! Nous avons
fait en sorte dans notre programme qu’elles apparaissent correctement en cherchant à quelle
ligne et quelle colonne commencer pour avoir le bon résultat. Une recherche plus approfondie
doit permettre cependant d’écrire vraiment n’importe où sur l’écran.
Ainsi, il est également possible de donner l’impression que le texte défile et changeant
peu à peu sa place à chaque nouvel écran. Par manque de temps, nous ne sommes pas allés
jusque là. La suite serait probablement de créer une véritable animation avec des couleurs
changeante et clignotante, enfin tant qu’on respecte la capacité de mémoire de notre carte.

- 16 -

Das könnte Ihnen auch gefallen