Beruflich Dokumente
Kultur Dokumente
Chauvin Caroline
Projet VHDL :
Affichage sur écran VGA
ENSEIRB 2004
Sommaire
V- Personnalisation du projet......................................................................... - 12 -
-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;
BEGIN -- perso
un_seul : PROCESS
VARIABLE x,y : natural := 0; --initialisation des compteurs
BEGIN
WAIT UNTIL rising_edge(clk_24Mhz); --synchronisation sur l’horloge
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;
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;
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.
-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
BEGIN -- PROCESS p3
WAIT UNTIL rising_edge(clk_24Mhz); --synchronisation sur l’horloge
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.
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;
BEGIN -- pixel
rgb <=
coul & "0000" & coul & "0000" WHEN pixel='1'
ELSE "1111" & coul & "1111" & coul;
END pixel;
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
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));
END poppins;
- 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.
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 -