Aller au contenu

Un générateur de signaux vidéo

ATTENTION

TAG GIT pour cette ETAPE : VGA

Objectif

l s'agit de construire le code d'un dispositif générant des signaux vidéo et les signaux de synchronisation associés permettant de contrôler un écran LCD. De plus, nous voulons plus qu'un simple code qui marche, mais bel et bien un code paramétrable et réutilisable.

Le générateur de signaux vidéo

La norme VGA (Video Graphics Array)

La norme d'affichage VGA a été conçue pour afficher des flux vidéo sur un moniteur. Il s'agit d'une suite de pixels correspondant au balayage ligne par ligne, puis colonne par colonne des pixels de l'écran. Le schéma de transmission reste très fortement influencé par les limitations des anciens moniteurs analogiques.

  • L'horloge pixel n'était pas transmise, mais on indiquait un début d'image ou un début de ligne par une signalisation particulière.
  • Pour permettre au faisceau électronique d'avoir le temps de revenir en début de chaque ligne, ou en début de chaque image, l'image était transmise en ménageant des intervalles de temps neutres (entre lignes et entre images). Ces intervalles sont appelés intervalles de suppression ou blanking en anglais.

Cela aboutit au schéma de transmission suivant pour notre carte DE10-Nano:

  • Le flux vidéo est cadencé par l'horloge pixel_clk.
  • Chaque pixel RGB est un mot de 24 bits, contenant les 3 composantes colorées Rouge, Vert et Bleu codées chacune sur 8 bits.
  • Chaque image est transmise de haut en bas ligne par ligne.
  • Chaque ligne est transmise de gauche à droite pixel par pixel.
  • Le début d'une image est signalé par un signal de synchronisation spécifique VS pour Vertical Synchro actif à l'état bas.
  • Le début d'une ligne est signalé par un signal de synchronisation spécifique HS pour Horizontal Synchro actif à l'état bas.
  • Les intervalles de suppression ou blanking , c'est-à-dire sans transmission de pixel, sont signalés par un signal spécifique BLANK actif à l'état bas.
  • Les durées des lignes, des images, des signaux de synchronisation et des intervalles de blanking sont normalisées (en nombre de cycles de pixel_clk) et doivent être respectées pour garantir la bonne synchronisation de l'écran.

L'évolution temporelle des signaux peut être représentée sur un diagramme temporel à deux dimensions (la dimension horizontale correspondant aux pixels, la dimension verticale correspondant aux lignes).

La trame vidéo

Les paramètres temporels choisis pour notre affichage LCD sont les suivant :

Paramètre Commentaire Valeur Unité
Fpix fréquence pixel 32 Mhz
Fdisp fréquence image 66 images/sec
HDISP Largeur de l'image affichée 800 pixels
VDISP Hauteur de l'image affichée 480 lignes
HFP Horizontal Front Porch 40 pixels
HPULSE Largeur de la synchro ligne 48 pixels
HBP Horizontal Back Porch 40 pixels
VFP Vertical Front Porch 13 lignes
VPULSE Largeur de la sync image 3 lignes
VBP Vertical Back Porch 29 lignes

1/ Squelette du contrôleur VGA

A vous de jouer

Dans le répertoire SoCFPGA/src, créez un fichier vga.sv qui contiendra un module nommé vga.

Pour simplifier la définition des entrées/sorties, nous avons préparé la définition d'une interface video_if dans le fichier ips/interfaces/video_if.sv.

Créez le squelette du module (module vga... endmodule) en lui attribuant les entrées/sorties suivantes :

Nom de l'entrée/sortie Type de l'entrée sortie Commentaire
pixel_clk Entrée Horloge entrante du module
pixel_rst Entrée Initialisation, actif à l'état haut
video_ifm Modport master de l'interface video_if Tous les signaux destinés à l'écran passeront par cette interface. Le module vga est un maître.

2/ Génération des signaux de synchro (dans le module vga)

Pour faire simple, il s'agit de ne générer que les signaux de synchronisation associés au flux video.

Le cœur du contrôleur est donc constitué de deux compteurs: un compteur de pixels dans une ligne, et un compteur de lignes dans une image.

  • Tous les signaux sont synchrones de l'horloge pixel_clk. Le signal de remise à zéro sera pixel_rst
  • Les constantes pour les timings seront fournies via des paramètres locaux (localparam) dont les noms sont indiqués dans le tableau des timings.
  • Les constantes HDISP et VDISP seront des paramètres (parameter) et devront pouvoir être modifiées lors de l'instantiation du module vga.
  • Les valeurs des paramètres par défaut seront celles correspondant à l'écran LCD de la maquette (image 800x480).
  • Le dimensionnement des différents compteurs (nombre de bits) et les différentes comparaisons de valeurs devront se faire par calcul à partir des paramètres prédéfinis, à l'exclusion de tout codage en "dur" de constantes.
  • Les signaux de synchronisation (video_ifm.HS, video_ifm.VS, video_ifm.BLANK) seront calculés à partir de l'état des compteurs pixels et lignes. Ils devront eux-mêmes être synchrones.
  • Enfin, le signal video_ifm.CLK sera simplement pixel_clk.

Ne cherchez pas à simuler pour l'instant, compilez éventuellement directement avec /comelec/softs/bin/vlog vga.sv pour vérifier la syntaxe.

3/ Génération d'une mire (dans le module vga)

Il s'agit de générer une image calculée à la volée pour vérifier le bon fonctionnement de l'ensemble du module. La mire demandée sera très simple:

  • Un fond noir, des colonnes blanches tous les 16 pixels, des lignes blanches toutes les 16 lignes. Attention, les signaux de couleur sont codés sur 8 bits (min=0, max=255)
  • Générez le signal video_ifm.RGB de manière synchrone de façon à créer la mire en vous appuyant sur les valeurs des compteurs de la synchronisation. Les octets R, G et B sont concaténés dans le mot RGB sous la forme d'un vecteur {R,G,B}.
  • Attention: avant de générer la mire, il peut être utile de calculer des coordonnées relatives des pixels actifs à partir des compteurs, de façon a obtenir une coordonnée (0,0) pour le premier pixel actif de l'image.

Ne cherchez pas à simuler pour l'instant, compilez éventuellement directement avec /comelec/softs/bin/vlog vga.sv pour vérifier la syntaxe.

4/ Mise à jour du module Top pour intégrer le module vga.

Le contrôleur vga est un sous-module de Top . Vous l'intégrerez de la façon suivante:

  • Créez une instance de vga dans Top.
  • Connectez le signal pixel_clk au signal de même nom de votre instance (l'horloge à 32 Mhz)
  • Connectez le signal pixel_rst au signal de même nom de votre instance.
  • Enfin, connectez le port d'interface video_ifm à une interface de même nom (qui n'existe pas encore)

Cette dernière interface doit être directement connectée au monde extérieur (la vidéo doit sortir du FPGA...):

  • Modifier la liste des entrées/sorties de Top en ajoutant un port nommé video_ifm de modport de type master d'une interface de type video_if (la syntaxe est identique à celle utilisée dans vga).
  • Enfin, rendez le module Top paramétrable:
    • Ajoutez deux paramètres HDISP et VDISP ayant pour valeurs par défaut 800 et 480.
    • Modifiez l'instanciation de vga de façon à ce que les paramètres HDISP et VDISP ainsi créés se propagent à vga.

Ne cherchez pas à simuler pour l'instant, compilez éventuellement directement avec /comelec/softs/bin/vlog Top.sv pour vérifier la syntaxe.

5/ Mise à jour du testbench de fpga pour évaluer votre générateur VGA.

La véritable interface video_if à laquelle est connecté le contrôleur vga via le module Top doit être instanciée dans le tesbench:

  • Dans tb_Top.sv, ajoutez une instance de video_if. Donnez-lui un nom quelconque, par exemple video_if0.
video_if video_if0() ;
  • Modifiez l'instanciation de Top de façon à ce que les paramètres HDISP et VDISP soient forcés à 160 et 90. Il s'agit, une fois de plus, de limiter en simulation le nombre de cycles à attendre de manière raisonnable tout en conservant en synthèse les valeurs par défaut.
  • Connectez le module Top à l'interface video video_if0.

6/ Première simulation

Lancez la simulation en mode graphique, visualisez les signaux importants (ceux de l'interface video_if0) et tentez de vérifier visuellement le bon comportement de votre contrôleur vga.

7/ Une vérification plus complète

Nous avons préparé pour vous un module screen "testeur" de signaux vga. Ce testeur a deux fonctions:

  • Vérifier la validité des signaux de synchronisation en fonction du mode souhaité.
  • Créer des fichiers contenant les images générées par votre code.

Modifiez tb_Top de manière à instancier le module screen connecté à l'interface video_if0 . Cela devrait ressembler à quelque chose comme ceci:

 screen #(.mode(13),.X(160),.Y(90)) screen0(.video_ifs(video_if0))  ;

Le paramètre mode égal à 13 permet de sélectionner des paramètres de synchro d'images correspondant à votre écran LCD, les paramètres X et Y permettent d'ajuster la taille de l'image à quelque chose de plus raisonnable. Évidemment vous devez choisir les mêmes que ceux choisis pour instancier Top.

Relancez la simulation (le mode batch suffit).

  • Vous devriez voir apparaître des messages d'erreur explicites sur le non-respect des valeurs attendues.
  • Si vous êtes chanceux, les seuls messages indiquent les générations successives d'images. Après la simulation, vous pouvez afficher les images générées:
eog work/*.ppm**

Si les images générées ne sont pas toutes identiques, c'est qu'il y a encore un problème (nombre de lignes de l'image incorrect ?...)

8/ Préparation de la synthèse à la nouvelle version du code

Il faut adapter les scripts de synthèse pour tenir compte des nouveaux fichiers et des nouvelles entrées sorties.

Définitions des pattes d'entrée/sortie: fichier syn/scripts/pins_assignement.tcl

Nous avons préparé un fichier de contraintes spécifique pour les entrées sorties VGA. Vous devez simplement modifier le fichier pins_assignement.tcl en supprimant le commentaire dans la ligne incluant le source pins_assignement_vga.tcl. Le résultat devrait être:

# Le E/S du contrôleur VGA
source pins_assignment_vga.tcl

Liste des fichiers pour la synthèse: fichier syn/scripts/project_list.tcl

  • Compléter le fichier project_list.tcl par les définitions des nouveaux fichiers source nécessaires au module vga. Il s'agit des fichiers suivants:
    • $PROJECT_DIR/ips/interfaces/video_if.sv
    • $PROJECT_DIR/SoCFPGA/src/vga.sv

Attention les définitions doivent être placées avant celle du fichier Top.sv

9/ Synthèse

  • Synthétisez votre design, corrigez les erreurs.
  • En ce qui concerne les Warnings, interrogez vos encadrants pour déterminer s'ils sont importants ou non.

10/ Test sur la maquette

  • Programmez votre maquette (make program)
  • Faites un reset de la maquette (key[0])/
  • Et constatez le bon fonctionnement éventuel.
  • Si cela ne fonctionne pas, revérifiez toutes les étapes.

Conclusion

  • Nous sommes maintenant prêts à stocker les images en mémoire (framebuffer) plutôt que de les générer à la volée. C'est l'objectif de l'étape suivante.

N'OUBLIEZ PAS

TAG GIT pour cette ETAPE : VGA