Créer un module IP avec Vivado

Introduction

Les deux premiers projets ont permis de se familiariser à Vivado en privilégiant deux aspects :

Il s'agit maintenant de marier ces deux mondes en créant un module IP maison décrit en VHDL. Ce module pourra ensuite être intégré à un projet de système complet intégrant un coeur de processeur comme dans l'exercice précédent.

Création d'un nouveau périphérique AXI4

Créer un projet de type RTL (comme dans l'exemple précédent) et le nommer Projet_IP_PWM.

Note : le projet créé est totalement vierge et doit être configuré pour cibler une carte Zybo comme dans le projet VHDL vu précédemment.

Il s'agit de créer un module IP capable de s'interconnecter au Processing System via un bus AXI. Ce type de module est connu sous l'appellation de périphérique AXI4.

Lancer le processus de création par le menu Tools -> Create and Package New IP.

Passer la première boite de dialogue d'information en cliquant sur Next.

La boite de dialogue suivante apparaît :

Création d'un module IP

Choisir Create a new AXI4 peripheral puis cliquer sur Next.

Compléter le dialogue qui apparaît comme suit (champs Name et Description) :

Nom et description du module IP

Noter que le dossier d'accueil de l'IP créé est noté ip_repo et ne se trouve pas par défaut dans le dossier du projet en cours.

On sélectionne ensuite les caractéristiques du module IP en conservant les propositions faites par défauts :

Caractéristiques du module IP

Valider par Next.

Le processus préliminaire de création se termine par la boite ci-dessous dans laquelle on sélectionne Edit IP avant de cliquer sur le bouton Finish.

Vers l'édition du module IP

Génération du signal PWM 16 bits

On se propose de réaliser en VHDL un module PWM 16 bits à l'image de celui disponible dans les microcontrôleurs.

Principe de fonctionnement

Il s'agit de générer un signal carré de période $T$ fixée et au rapport cyclique commandable sur 16 bits. Le résultat prend la forme suivante où $pwm\_out$ est le signal généré :

Signal PWM

L'intérêt : obtenir un signal continu dont la valeur moyenne $‹pwm_{out}›=\alpha.V_{CCio}$ soit réglable.

La figure ci-dessus fait apparaître les éléments nécessaires à la génération d'un tel signal. On met d'abord en place un compteur, intitulé ici $pwm\_counter$, comptant de 0 à 65535 donc sur 16 bits non signés. La période de comptage à retenir est donc de $T_{comptage}=\frac{T}{2^{16}}$, ce qui conduit à une fréquence de comptage de $F_{clk}=\frac{2^{16}}{T}$.

Cahier des charges

Le bloc hiérarchique du module PWM à réaliser est le suivant :

Générateur PWM

Y figurent les signaux suivants :

Le calcul du rapport de prédivision $N$ se fait aisément avec la relation suivante : $N=2^{prescaler}$

Tâches à réaliser

  1. Créer un nouveau fichier source VHDL nommé pwm16bits_core (voir note juste après pour le chemin où stocker ce fichier) et le caractériser avec les entrées et sorties répondant au cahier des charges.
    Note importante : imposer le chemin du fichier pwm16bits_core de sorte qu'il se retrouve dans le dossier ip_repo/ip_pwm16bits_1.0/hdl (le dossier ip_repo se trouve par défaut dans le même dossier que vos projets Vivado).
  2. Décrire le module en VHDL (sans gérer le prescaler pour commencer).
  3. Simuler le projet :
    1. soit en créant les stimulii de manière graphique,
    2. soit en ajoutant un fichier de test VHDL nommé pwm16bits_core_tb et en écrivant les process permettant de générer des signaux pertinants pour valider et simuler le comportement du code écrit à la question précédente.
      Note : pour apprendre à créer un testbench, il est recommandé de voir la vidéo Cours de VHDL #6. Process et écriture des bancs de test.
      Attention : pour simuler le code pwm16bits_core, il faut que ce fichier soit placé en sommet de hiérarchie dans les sources de simulation comme présenté ci-dessous :
      set as top
  4. Reprendre les deux dernières étapes en ajoutant le prescaler.

Aides : la mise en place du prescaler se fait aisément en lui associant un compteur décomptant de $N-1$ à $0$ et en autorisant le comptage sur $pwm\_counter$ au moment des passages à 0 du compteur associé au prescaler.

Conseils supplémentaires :

Intégration du code dans l'IP

L'étape Création d'un nouveau périphérique AXI4 a abouti à la création de la structure de base du module IP. A cette occasion, deux fichiers VHDL ont été produits :

2 sources VHDL pour un IP

Les deux fichiers créés sont hiérarchiquement dépendants.

ip_pwm16bits_v1_0.vhd est le sommet de la hiérarchie de notre IP. C'est à partir de ce fichier que le bloc fonctionnel apparaissant dans le diagramme sera élaboré.

ip_pwm16bits_v1_0_S00_AXI.vhd est instancié par le fichier précédent. Ce fichier met en oeuvre l'interface AXI pour assurer les échanges avec le Processing System (PS). Rappelons que ce fichier VHDL sera implémenté dans le Programmable Logic (PL). Il instancie le composant que nous avons créé dans le fichier pwm16bits_core.vhd, lequel conserve l'avantage d'occulter tout ce qui correspond au bus AXI pour une simulation simplifiée.

La suite propose d'ajouter notre composant pwm16bits_core.vhd au fichier ip_pwm16bits_v1_0_S00_AXI.vhd et de l'instancier. Il faudra également faire remonter le signal pwm créé par notre code VHDL jusqu'au sommet de la hiérarchie de l'IP créé, c'est à dire au niveau du fichier ip_pwm16bits_v1_0.vhd.

En dehors des signaux du bus AXI tous déjà définis par le processus précédent, il nous faut maintenant ajouter les signaux que nous allons créer. Dans un premier temps, on se contente d'ajouter une sortie PWM de type STD_LOGIC.

Cette sortie est d'abord ajoutée au niveau du sommet hiérarchique de notre IP donc dans la liste des ports du fichier ip_pwm16bits_v1_0.vhd comme suit :

Ajout des ports

A noter que cet ajout s'effectue dans la zone identifiée à cet effet par le générateur d'IP par le commentaire -- Users to add ports here.

Comme ce signal PWM sera également présent dans le fichier de description du coeur de notre IP (ip_pwm16bits_v1_0_S00_AXI.vhd), on met à jour la description du composant qui en est faite dans ip_pwm16bits_v1_0.vhd comme suit :

Ajout des ports au composant qui sera instancié

Finalement on ajoute l'information de routage entre le fichier d'instanciation et le fichier instancié dans ip_pwm16bits_v1_0.vhd, fichier dont les modifications sont maintenant terminées.

Routage de l'instance

On s'attaque maintenant à la description de la fonction réalisée par l'IP à proprement parler dans le fichier ip_pwm16bits_v1_0_S00_AXI.vhd.

Logiquement, on commence par ajouter le port pour la sortie pwm :

Ajout du port pwm ...

On va maintenant déclarer le composant pwm16bits_core dans le fichier ip_pwm16bits_v1_0_S00_AXI.vhd dans la zone réservée pour les signaux "utilisateur" (on peut aussi y déclarer des composants).

Déclaration du core pwm

Composant qu'il faut instancier pour terminer à la toute fin du fichier ip_pwm16bits_v1_0_S00_AXI.vhd :

Instanciation du core pwm

Noter qu'on utilise ici deux signaux particuliers de l'interface AXI :

  1. S_AXI_ACLK qui correspond au signal d'horloge qui ryhtme le bus AXI.
  2. slv_reg0, registre présent à l'adresse de base dans le Processing System (PS) du module IP que nous venons de créer et qui fournira la valeur du prescaler.
  3. slv_reg1, registre présent à l'adresse de base + 1 dans le Processing System (PS) du module IP que nous venons de créer et qui fournira la valeur de pwm_in.

Sauvegarder les fichiers VHDL édités durant cette partie pour finir.

Encapsulation de l'IP

Pour lancer le processus d'encapsulation, cliquer sur Package IP dans la section PROJECT MANAGER du Flow Navigator.

Les informations suivantes apparaissent dans le PROJECT MANAGER :

Résultat de l'encapsulation

Mettre à jour l'IP en sélectionnant les paramètres qui ne sont pas à jour et ne sont pas pointés par une coche verte et en cliquant sur le message en haut de l'image précédente intitulé Merge changes from Customization Parameters Wizard.

Tout passe alors au vert :

Mise à jour des paramètres de l'IP

Noter que ces dernières opérations ont permis de prendre en compte les ajouts effectués dans les fichiers VHDL de l'IP, ce que l'on peut constater en listant la liste des ports intégrant dorénavant le signal pwm16bits :

Mise à jour des ports de l'IP

Terminer en configurant les paramètres d'édition de l'encapsultation en sélectionnant l'étape Review and Package :

Paramètres d'encapsulation de l'IP

et en réencapsulant l'IP par un clic sur le bouton Re-Package IP.

L'IP pwm 16 bits peut maintenant être utilisée dans un projet.

Utilisation de l'IP créée

Création de la structure matérielle

Ouvrir le projet nommé Projet_IP_PWM et créer un diagramme semblable à celui du TP Projet SoC avec Xilinx Vivado en reprenant toutes les étapes vues dans ce précédent TP. La seule nuance consistera à connecter les boutons poussoirs sur l'IP GPIO plutôt que les LEDs comme c'était le cas dans le TP précédent.

Ajouter une instance de l'IP pwm en prenant soin d'utiliser les commandes d'automatisation pour en assurer la connexion au reste de la structure de sorte d'aboutir au schéma suivant :

Ajouter également un port de sortie au diagramme et le relier à la sortie pwm16bits de l'IP pwm.

Le diagramme obtenu devra ressembler à cela :

 

Schéma du projet avec l'IP PWM

Si le diagramme est conforme à la figure ci-dessus, passer directement à l'étape d'implémentation. Sinon, il se peut que le signal pwm16bits n'apparaisse pas sur notre ip_pwm16bits. Dans ce cas, procéder comme suit :

Edit in IP Packager

 

Re-package IP

De retour dans le projet Projet_IP_PWM, cliquer sur Report IP Status.

 report ip status

Enfin mettre à jour l'IP en cliquant sur le bouton Upgrade Selected :

upgrade selected

On termine par un clic sur le bouton Generate dans la boite de dialogue qui apparaît (concernant la fenêtre d'avertissements, la fermer par un clic sur le bouton OK).

Comme l'IP a été mis à jour, on regénère le status des IP par un clic sur Rerun dans l'onglet IP Status :

Rerun ip status

A l'issue de ces étapes, la sortie doit maintenant apparaître sur l'ip_pwm16bits_0 présent dans le diagramme.

Implémentation...

Avant l'implémentation proprement dite, n'oubliez pas d'ajouter un fichier de conraintes au projet à l'image de ce qui a été fait dans le premier projet (Projet VHDL avec Xilinx Vivado). Ici, il suffira d'imposer la broche M14 du Zynq pour led_LD0 (signal en sortie de type LVCMOS33).

Implémenter le module, générer le bitstream de configuration et l'exporter pour l'utiliser sous le SDK.

Développement de l'application

Lancer le SDK.

Céer une nouvelle application nommée test_pwm sur la base du fichier source du projet précédent.

En vous inspirant du programme écrit dans le TP précédent, écrire un programme qui relève la valeur des 4 boutons poussoirs et qui fixe les 4 bits de poids fort du rapport cyclique du PWM à la valeur des 4 boutons poussoirs de sorte que le rapport cyclique s'écrivre BP3 BP2 BP1 BP0 0000 0000 0000 sous forme binaire.

Aide : consulter le fichier include créé pour l'IP PWM 16 bits afin de savoir comment envoyer les données nécessaires à la configuration de l'IP pour un rapport cyclique donné. On fixera le prescaler à 1.

Include de l'IP PWM 16 bits