Leçon 20 sur 22

Chapitre 20 — Interfaces numériques simples

Objectif — Finalité du chapitre

Comprendre les principes des communications UART, SPI et I²C, puis mettre en œuvre un générateur PWM et un émetteur UART utilisables dans un système FPGA.

Objectifs pédagogiques

À la fin de ce chapitre, l’étudiant devra être capable de :

  • distinguer transmission parallèle et transmission série ;
  • calculer un débit binaire et la durée d’une trame ;
  • décrire une trame UART 8N1 ;
  • concevoir un générateur de baud rate ;
  • concevoir un émetteur UART simple ;
  • expliquer le principe d’un récepteur UART suréchantillonné ;
  • identifier les signaux d’un bus SPI et ses quatre modes ;
  • décrire un échange SPI à l’aide d’un registre à décalage ;
  • expliquer les conditions START, STOP et ACK d’I²C ;
  • comprendre le fonctionnement électrique en drain ouvert ;
  • générer un signal PWM paramétrable ;
  • piloter la luminosité d’une LED ou la puissance moyenne d’un actionneur.

Prérequis

  • machines à états finis ;
  • compteurs et générateurs de tick ;
  • registres à décalage ;
  • entrées asynchrones et synchronisation ;
  • contraintes d’E/S et d’horloge ;
  • bancs de test automatisés.

Organisation du chapitre

Section

Contenu

Compétence principale

20.1Communication sérieLire une trame et calculer un débit
20.2UARTÉmettre et recevoir des octets
20.3SPIÉchanger des mots synchrones
20.4I²CComprendre un bus adressé ouvert
20.5PWMCommander une puissance moyenne
TP 16Interfaces et communicationsImplanter PWM, UART et SPI

 

Concept clé — Logique et couche électrique

Une description VHDL définit la logique numérique. Le fonctionnement réel dépend aussi des niveaux électriques, du câblage, des résistances, des convertisseurs USB-série et des contraintes de broches.

 

20.1 Communication série

Une interface numérique transmet des données entre blocs ou circuits. La communication peut être parallèle ou série, synchrone ou asynchrone.

20.1.1 Transmission parallèle

Plusieurs bits sont transmis simultanément sur plusieurs conducteurs.

Avantages

Limites

Mot complet en un transfertNombre élevé de broches
Logique simple à courte distanceSkew entre les lignes
Débit élevé à faible fréquenceCâblage plus complexe
Adaptée aux bus internesMoins adaptée aux longues distances

 

20.1.2 Transmission série

Les bits sont transmis successivement sur un nombre réduit de lignes.

Avantages

Limites

Peu de conducteursSérialisation et désérialisation
Câblage simpleLatence d’une trame
Adaptée aux périphériquesSynchronisation nécessaire
Possibilité de longues distances selon le standardDébit utile inférieur au débit brut

 

20.1.3 Débit binaire

Le débit binaire est le nombre de bits transmis par seconde. En UART, on parle souvent de baud rate ; pour une modulation binaire simple, un symbole représente un bit.

Débit

Durée approximative d’un bit

9 600 bit/s104,167 µs
57 600 bit/s17,361 µs
115 200 bit/s8,681 µs
1 Mbit/s1 µs

 

20.1.4 Débit brut et débit utile

Les bits de contrôle réduisent la part consacrée aux données utiles.

Rendement d’une trame UART 8N1  |  Calcul
8 bits de données
+ 1 bit de départ
+ 1 bit d'arrêt
= 10 bits transmis

RENDEMENT = 8 / 10 = 80 %

 

20.1.5 Trame de données

Une trame regroupe des bits selon un ordre défini : synchronisation, données, contrôle d’erreur et fin.

Élément

Rôle

Préambule ou STARTRepérer le début
AdresseSélectionner un destinataire
DonnéesTransporter l’information
Parité ou CRCDétecter certaines erreurs
ACKConfirmer une réception
STOPMarquer la fin

 

20.1.6 Ordre des bits

Les protocoles précisent si le bit de poids faible ou fort est transmis en premier. L’UART envoie habituellement le LSB en premier ; SPI peut être configuré.

20.1.7 Synchronisation

Communication synchrone

Communication asynchrone

Une horloge est transmise ou partagéePas d’horloge transmise continuellement
SPI, I²CUART
Échantillonnage défini par SCLK/SCLRécepteur reconstruit le timing du bit
Fréquence contrôlée par le maîtreÉmetteur et récepteur configurés au même débit

 

20.1.8 Duplex

Mode

Description

Exemple

SimplexUn seul sensCapteur émetteur uniquement
Half-duplexDeux sens, pas simultanémentBus partagé
Full-duplexDeux sens simultanésSPI avec MOSI/MISO, UART TX/RX

 

20.1.9 Erreurs de transmission

  • mauvais débit ;
  • mauvaise polarité ;
  • ordre des bits incorrect ;
  • échantillonnage sur le mauvais front ;
  • niveau électrique incompatible ;
  • bruit et intégrité du signal ;
  • perte d’octets faute de buffer.

20.1.10 Adaptation électrique

Sécurité électrique — UART logique ≠ RS-232

Une sortie FPGA LVCMOS ne doit pas être connectée directement à une interface RS-232 classique. Un convertisseur de niveau adapté ou un pont USB-UART compatible avec la tension de la carte est nécessaire.

 

20.2 Introduction à l’UART

L’UART, Universal Asynchronous Receiver/Transmitter, transmet des trames sans ligne d’horloge. Les deux extrémités doivent partager les mêmes paramètres.

20.2.1 Ligne au repos et bit de départ

La ligne TX est généralement à 1 au repos. Le bit de départ force la ligne à 0 pendant une durée de bit.

État

TX

Repos1
START0
DonnéesLSB en premier
Parité éventuelleSelon configuration
STOP1

 

20.2.2 Bits de données

Les formats usuels comportent 7, 8 ou 9 bits. Le format 8 bits est le plus courant pour les octets.

Ordre d’un octet xA5  |   Chronologie
xA5 = 1010 0101

Transmission LSB d'abord :
bit0, bit1, ..., bit7
1, 0, 1, 0, 0, 1, 0, 1

 

20.2.3 Bit de parité

Mode

Règle

AucunePas de bit de parité
PaireNombre total de 1 pair
ImpaireNombre total de 1 impair
MarkBit forcé à 1
SpaceBit forcé à 0

 

La parité détecte certaines erreurs simples, mais ne remplace pas un contrôle plus robuste comme un CRC.

20.2.4 Bit d’arrêt

Un ou plusieurs bits d’arrêt maintiennent la ligne à 1 et terminent la trame. Un récepteur peut signaler une erreur de framing si le niveau attendu n’est pas présent.

20.2.5 Notation 8N1

Symbole

Signification

8Huit bits de données
NNo parity, aucune parité
1Un bit d’arrêt

 

20.2.6 Durée d’une trame

Exemple à 115 200 bit/s  |  Calcul
Trame 8N1 = 10 bits

DUREE = 10 / 115200
      ≈ 86,81 microsecondes

Débit utile maximal théorique :
115200 * 8 / 10
= 92160 bit/s utiles

 

20.2.7 Générateur de baud rate

Le générateur produit une impulsion d’un cycle à chaque durée de bit. Pour une division entière : DIVISEUR = F_CLK / BAUD.

Entité  |   VHDL
entity generateur_baud is
    generic (
        F_CLK_HZ : positive := 50_000_000;
        BAUD     : positive := 115_200
    );
    port (
        clk   : in   std_logic;
        reset : in  std_logic;
        tick  : out std_logic
    );
end entity generateur_baud;

 

20.2.8 Division entière et erreur

Fclk

Baud demandé

Diviseur arrondi

Baud obtenu

50 MHz115 200434≈ 115 207
100 MHz115 200868≈ 115 207
50 MHz9 6005 208≈ 9 600,6

 

L’erreur relative doit rester compatible avec la tolérance globale de l’émetteur et du récepteur.

20.2.9 Architecture du générateur

Générateur de baud — Initialisation  |  VHDL
architecture rtl of generateur_baud is
    constant DIVISEUR : positive :=
        (F_CLK_HZ + BAUD/2) / BAUD;

    signal compteur : natural range 0 to DIVISEUR-1 := 0;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                compteur <= 0;
                tick <= '0';
            else
                tick <= '0';
Générateur de baud — Comptage et tick  |  VHDL
                if compteur = DIVISEUR-1 then
                    compteur <= 0;
                    tick <= '1';
                else
                    compteur <= compteur + 1;
                end if;
            end if;
        end if;
    end process;
end architecture rtl;

 

20.2.10 Générateur par accumulateur de phase

Pour améliorer la moyenne lorsque le rapport n’est pas entier, un accumulateur peut produire des intervalles alternés. Cette méthode introduit un léger jitter déterministe mais une fréquence moyenne plus précise.

Principe d’accumulateur  |  Principe
accumulateur <= accumulateur + INCREMENT;

if retenue = '1' then
    tick <= '1';
else
    tick <= '0';
end if;

 

20.2.11 Émetteur UART : états

État

Action

IDLETX=1, attente de start
START_BITTX=0 pendant un bit
DATA_BITSEnvoi de 8 bits LSB d’abord
STOP_BITTX=1 pendant un bit

 

20.2.12 Entité de l’émetteur

uart_tx.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity uart_tx is
    port (
        clk       : in   std_logic;
        reset     : in   std_logic;
        baud_tick : in  std_logic;
        start     : in   std_logic;
        data_in   : in   std_logic_vector(7 downto 0);
        tx        : out std_logic;
        busy      : out std_logic;
        done      : out std_logic
    );
end entity uart_tx;

 

20.2.13 Émetteur : déclarations

uart_tx.vhd — Signaux  |  VHDL
architecture rtl of uart_tx is
    type etat_t is (IDLE, START_BIT, DATA_BITS, STOP_BIT);
    signal etat : etat_t := IDLE;

    signal registre : std_logic_vector(7 downto 0)
                      := (others => '0');
    signal index_bit : natural range 0 to 7 := 0;
begin

 

20.2.14 Émetteur : processus

uart_tx.vhd — FSM, partie 1  |  VHDL
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                etat <= IDLE;
                registre <= (others => '0');
                index_bit <= 0;
                tx <= '1';
                busy <= '0';
                done <= '0';
            else
                done <= '0';

                case etat is
                    when IDLE =>
                        tx <= '1';
                        busy <= '0';

                        if start = '1' then
                            registre <= data_in;
                            index_bit <= 0;
                            busy <= '1';
                            etat <= START_BIT;
                        end if;

 

uart_tx.vhd — FSM, partie 2  |  VHDL
                    when START_BIT =>
                        tx <= '0';
                        busy <= '1';

                        if baud_tick = '1' then
                            etat <= DATA_BITS;
                        end if;

                    when DATA_BITS =>
                        tx <= registre(index_bit);
                        busy <= '1';

                        if baud_tick = '1' then
                            if index_bit = 7 then
                                etat <= STOP_BIT;
                            else
                                 index_bit <= index_bit + 1;
                            end if;
                        end if;

 

uart_tx.vhd — FSM, partie 3  |  VHDL
                    when STOP_BIT =>
                        tx <= '1';
                        busy <= '1';

                        if baud_tick = '1' then
                            busy <= '0';
                            done <= '1';
                            etat <= IDLE;
                        end if;
                end case;
            end if;
        end if;
    end process;
end architecture rtl;

 

20.2.15 Chronologie de start

Le signal start doit être une impulsion d’un cycle lorsque busy=0. L’octet est mémorisé immédiatement, puis le bit START est présenté jusqu’au tick de baud suivant.

20.2.16 Récepteur UART : principe

  • synchroniser rx dans le domaine clk ;
  • détecter le passage de 1 à 0 ;
  • attendre le milieu du bit START ;
  • échantillonner chaque donnée au centre de sa cellule ;
  • reconstruire l’octet LSB en premier ;
  • vérifier le bit STOP ;
  • produire data_valid ou framing_error.

20.2.17 Suréchantillonnage

Un récepteur utilise souvent 8 ou 16 échantillons par bit. Il repère le centre et peut effectuer un vote majoritaire.

Suréchantillonnage

Avantage

×1Logique simple, synchronisation moins robuste
×8Centre du bit mieux localisé
×16Standard pédagogique fréquent, vote possible

 

20.2.18 États d’un récepteur

État

Action

IDLEAttente d’un niveau bas
STARTValidation au centre du bit
DATAÉchantillonnage des huit bits
STOPContrôle du niveau haut
VALIDImpulsion octet reçu

 

20.2.19 Erreurs UART

Erreur

Cause

Framing errorBit STOP non haut
Parity errorParité reçue différente
OverrunNouvel octet avant lecture de l’ancien
Baud mismatchDébits trop différents
Glitch STARTImpulsion basse trop courte

 

20.2.20 Bufferisation

Une FIFO permet de découpler l’UART de la logique consommatrice ou productrice. Sans buffer, start doit respecter busy et les octets reçus doivent être traités rapidement.

20.3 Introduction au protocole SPI

SPI est une interface série synchrone, généralement contrôlée par un maître. Elle n’impose pas un format unique de trame : les paramètres sont définis par les périphériques.

20.3.1 Signaux

Signal

Sens typique

Rôle

SCLKMaître → esclavesHorloge série
MOSIMaître → esclaveDonnée envoyée par le maître
MISOEsclave → maîtreDonnée renvoyée
CS_n / SS_nMaître → esclaveSélection active bas

 

20.3.2 Maître et esclave

  • le maître génère SCLK ;
  • le maître active un CS par périphérique ;
  • les deux côtés possèdent souvent un registre à décalage ;
  • l’échange est naturellement full-duplex ;
  • le sens et la longueur des mots dépendent du composant.

20.3.3 Sélection CS

CS_n est généralement placé à 0 avant les premiers fronts, maintenu pendant l’échange, puis remis à 1.

Protocole — Fiche technique

Certains périphériques exigent un temps minimal entre CS et le premier front, une pause entre mots ou un ordre précis des octets.

 

20.3.4 Modes SPI

Les modes sont définis par CPOL, niveau de repos de SCLK, et CPHA, choix du premier front d’échantillonnage.

Mode

CPOL

CPHA

SCLK au repos

Échantillonnage principal

000BasFront montant
101BasFront descendant
210HautFront descendant
311HautFront montant

 

20.3.5 Changement et échantillonnage

Une convention fréquente consiste à changer la donnée sur un front et à l’échantillonner sur l’autre. Les deux extrémités doivent utiliser le même mode.

20.3.6 Registre à décalage

Échange MSB en premier  |  VHDL
miso_capture <= registre_rx(6 downto 0) & miso;

mosi <= registre_tx(7);

registre_tx <= registre_tx(6 downto 0) & '0';

 

20.3.7 Diviseur de SCLK

Un compteur produit des impulsions de demi-période. SCLK est inversée à chaque impulsion pendant la transaction.

Fréquence SPI  |   Calcul
F_SCLK = F_CLK / (2 * DIVISEUR)

Exemple :
F_CLK = 50 MHz
DIVISEUR = 5
F_SCLK = 5 MHz

 

20.3.8 Maître SPI mode 0 : interface

spi_maitre_mode0.vhd — Entité  |  VHDL
entity spi_maitre_mode0 is
    generic (
        DIVISEUR : positive := 5
    );
    port (
        clk      : in   std_logic;
        reset    : in   std_logic;
        start    : in   std_logic;
        tx_data  : in   std_logic_vector(7 downto 0);
        miso     : in   std_logic;
        sclk     : out std_logic;
        mosi     : out std_logic;
        cs_n     : out std_logic;
        rx_data  : out std_logic_vector(7 downto 0);
        busy     : out std_logic;
        done     : out std_logic
    );
end entity spi_maitre_mode0;

 

20.3.9 Maître SPI : principe de FSM

État

Action

IDLECS=1, SCLK=0, attente start
TRANSFERCS=0, fronts SCLK et décalages
FINISHCS=1, done=1

 

20.3.10 Algorithme de transfert

Pseudo-VHDL du mode 0  |   Algorithme
-- Au démarrage :
registre_tx <= tx_data;
compteur_bits <= 0;
cs_n <= '0';
sclk <= '0';
mosi <= tx_data(7);

-- Front montant SCLK :
-- capturer MISO.

-- Front descendant SCLK :
-- décaler TX et présenter le bit suivant.

-- Après huit bits :
cs_n <= '1';
done <= '1';

 

20.3.11 MISO partagé

Avec plusieurs esclaves, les sorties MISO doivent être en haute impédance lorsqu’ils ne sont pas sélectionnés, ou être multiplexées selon la carte.

20.3.12 SPI sans adressage standard

SPI ne définit pas d’adresse de périphérique sur les données. La sélection est assurée par CS ou par un protocole applicatif propre au composant.

20.3.13 Avantages et limites

Avantages

Limites

Débit élevéPlusieurs fils
Full-duplexUn CS par esclave souvent nécessaire
Logique simplePas d’ACK standard
Modes configurablesProtocole applicatif variable

 

20.4 Introduction au protocole I²C

I²C est un bus série synchrone à deux fils permettant de connecter plusieurs contrôleurs et cibles adressées.

20.4.1 Signaux SDA et SCL

Signal

Rôle

SDADonnées bidirectionnelles
SCLHorloge du bus

 

20.4.2 Principe du bus ouvert

Les participants peuvent tirer la ligne à 0, mais ne doivent pas la forcer à 1. Des résistances de rappel ramènent SDA et SCL au niveau haut lorsque personne ne les force à 0.

Sortie drain ouvert conceptuelle  |  VHDL
sda <= '0' when sda_drive_low = '1'
       else 'Z';

scl <= '0' when scl_drive_low = '1'
       else 'Z';

 

Couche électrique — Résistances de pull-up

Sans résistances de rappel adaptées à la tension du bus, les lignes ne remontent pas correctement. Leur valeur dépend de la capacité du bus et de la vitesse.

 

20.4.3 Câblage d’E/S

Séparation entrée/commande  |  VHDL
sda_in <= sda;
scl_in <= scl;

-- La logique interne ne produit qu'une commande
-- 'tirer à zéro' ou 'relâcher'.

 

20.4.4 Condition START

START correspond à une transition de SDA de 1 vers 0 pendant que SCL reste à 1.

Condition logique observée  |  VHDL
start_detecte <= '1'
    when sda_precedent = '1'
     and sda_courant = '0'
     and scl_courant = '1'
    else '0';

 

20.4.5 Condition STOP

STOP correspond à une transition de SDA de 0 vers 1 pendant que SCL reste à 1.

20.4.6 Données stables

En dehors de START et STOP, SDA doit normalement rester stable lorsque SCL est haut. Les changements de données sont préparés pendant SCL bas.

20.4.7 Adressage

Une transaction classique commence par une adresse sur 7 bits suivie du bit R/W.

Bit R/W

Sens

0Écriture du contrôleur vers la cible
1Lecture de la cible vers le contrôleur

 

20.4.8 Adresse 7 bits et octet transmis

Construction  |   VHDL
octet_adresse <= adresse_7_bits & rw;

 

20.4.9 Acquittement ACK/NACK

Après huit bits, l’émetteur relâche SDA. Le récepteur tire SDA à 0 pendant le neuvième cycle pour ACK. Un niveau haut indique NACK.

SDA au 9e bit

Signification

0ACK : octet accepté
1NACK : absence d’acquittement

 

20.4.10 Transaction d’écriture

1. START.

2. Adresse + bit W=0.

3. ACK de la cible.

4. Octet de registre éventuel.

5. ACK.

6. Un ou plusieurs octets de données.

7. ACK après chaque octet.

8. STOP.

20.4.11 Transaction de lecture

1. START.

2. Adresse + bit R=1, ou séquence préalable d’adresse de registre.

3. ACK de la cible.

4. La cible transmet les données.

5. Le contrôleur envoie ACK pour continuer.

6. Le contrôleur envoie NACK sur le dernier octet.

7. STOP.

20.4.12 Repeated START

Un START répété permet de changer le sens ou de poursuivre une transaction sans libérer le bus.

20.4.13 Clock stretching

Une cible peut maintenir SCL à 0 pour ralentir le contrôleur. Un maître robuste doit lire le niveau réel de SCL avant de considérer le front haut comme atteint.

20.4.14 Arbitrage

Dans un bus multi-contrôleur, un participant qui relâche SDA mais lit 0 perd l’arbitrage. Le drain ouvert permet cette détection sans court-circuit.

20.4.15 FSM d’un contrôleur I²C

État

Action

IDLEBus relâché
STARTSDA bas pendant SCL haut
SEND_BITPrésenter les bits
SCL_HIGHRelâcher SCL et attendre son niveau haut
ACKRelâcher SDA et échantillonner
STOPSDA remonte pendant SCL haut

 

20.4.16 Vitesse et timing

Les vitesses et contraintes exactes dépendent du mode I²C et de la fiche technique des composants. Le contrôleur doit respecter les temps bas, hauts, setup et hold.

20.4.17 I²C dans un FPGA

  • utiliser des buffers E/S bidirectionnels ou une inférence tri-state au niveau supérieur ;
  • synchroniser les lectures SDA/SCL si elles sont traitées par clk ;
  • filtrer éventuellement de très courtes perturbations ;
  • gérer ACK, timeout, stretching et erreurs ;
  • tester avec un analyseur logique.

20.5 Modulation PWM

La modulation de largeur d’impulsion produit un signal périodique dont le rapport cyclique représente une valeur de commande.

20.5.1 Rapport cyclique

Définition  |   Calcul
D = TEMPS_HAUT / PERIODE

D = 0 %   : toujours bas
D = 50 %  : moitié haut, moitié bas
D = 100 % : toujours haut

 

20.5.2 PWM par compteur

Un compteur libre parcourt toute sa plage. La sortie vaut 1 lorsque le compteur est inférieur à la consigne.

PWM 8 bits  |   VHDL
process(clk)
begin
    if rising_edge(clk) then
        compteur <= compteur + 1;
    end if;
end process;

pwm <= '1'
    when compteur < unsigned(consigne)
    else '0';

 

20.5.3 Résolution

Bits

Niveaux

Pas approximatif

4166,25 %
82560,390625 %
101 0240,097656 %
124 0960,024414 %

 

20.5.4 Fréquence PWM

PWM à compteur libre  |  Calcul
F_PWM = F_CLK / 2^N

Exemple :
F_CLK = 50 MHz
N = 8
F_PWM ≈ 195,3125 kHz

 

20.5.5 PWM à fréquence configurable

Un prescaler génère un tick PWM, puis le compteur de phase avance à ce rythme.

Structure  |   VHDL
if rising_edge(clk) then
    if tick_pwm = '1' then
        phase <= phase + 1;
    end if;
end if;

pwm <= '1' when phase < duty else '0';

 

20.5.6 Gestion de 100 %

Avec une consigne 8 bits de 0 à 255 et la comparaison compteur < duty, la valeur 255 produit 255 cycles hauts sur 256, pas exactement 100 %. Une entrée séparée ou une consigne sur 9 bits peut représenter 256.

Traitement explicite  |  VHDL
if duty_full = '1' then
    pwm <= '1';
elsif phase < duty then
    pwm <= '1';
else
    pwm <= '0';
end if;

 

20.5.7 Générateur générique

pwm_generique.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity pwm_generique is
    generic (
        N : positive := 8
    );
    port (
        clk   : in   std_logic;
        reset : in  std_logic;
        duty  : in   unsigned(N-1 downto 0);
        pwm   : out std_logic
    );
end entity pwm_generique;

 

pwm_generique.vhd — Architecture  |  VHDL
architecture rtl of pwm_generique is
    signal phase : unsigned(N-1 downto 0)
                   := (others => '0');
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if reset = '1' then
                phase <= (others => '0');
            else
                phase <= phase + 1;
            end if;
        end if;
    end process;

    pwm <= '1' when phase < duty else '0';
end architecture rtl;

 

20.5.8 Variation de luminosité d’une LED

L’œil intègre les impulsions rapides. Le rapport cyclique modifie la luminosité moyenne perçue.

Duty approximatif

Luminosité moyenne

0 %Éteinte
25 %Faible
50 %Moyenne
75 %Forte
100 %Maximale

 

20.5.9 Perception non linéaire

La luminosité perçue n’est pas strictement proportionnelle au rapport cyclique. Une table gamma peut améliorer la progressivité visuelle.

Correction par table  |  VHDL
duty_corrige <= GAMMA_ROM(
    to_integer(unsigned(niveau))
);

 

20.5.10 Commande d’un moteur

La PWM peut commander la puissance moyenne d’un moteur via un transistor, un MOSFET ou un pont en H adapté.

Sécurité — Ne pas connecter un moteur au FPGA

Une broche FPGA ne doit pas alimenter directement un moteur. Il faut un étage de puissance, une protection contre les surtensions inductives et une alimentation correctement dimensionnée.

 

20.5.11 Fréquence pour moteur

Une fréquence trop basse peut produire du bruit audible ou des variations de couple. Une fréquence trop élevée augmente les pertes de commutation. Le choix dépend du moteur et de l’étage de puissance.

20.5.12 PWM centrée

Une PWM à compteur montant-descendant place les fronts plus symétriquement dans la période. Elle est utilisée dans certaines commandes de puissance.

20.5.13 Mise à jour sans glitch

Changer duty au milieu d’une période peut produire une impulsion exceptionnellement longue ou courte. Une solution consiste à enregistrer la nouvelle consigne au début de la période.

Mise à jour au retour de phase  |  VHDL
if rising_edge(clk) then
    phase <= phase + 1;

    if phase = 0 then
        duty_actif <= duty_demande;
    end if;
end if;

pwm <= '1' when phase < duty_actif else '0';

 

Méthode de conception d’une interface

1. Lire la fiche technique du périphérique.

2. Identifier les signaux, leur direction et leur polarité.

3. Définir fréquence, débit et format des trames.

4. Choisir une architecture à FSM.

5. Dimensionner les compteurs et registres.

6. Traiter les entrées asynchrones.

7. Définir busy, done, valid et error.

8. Créer un banc de test reproduisant les timings.

9. Ajouter les contraintes de broches et d’horloge.

10. Valider au moyen d’un analyseur logique ou d’un terminal.

Checklist

  • Les niveaux électriques sont-ils compatibles ?
  • Le débit réel respecte-t-il la tolérance ?
  • L’ordre des bits est-il correct ?
  • Le front d’échantillonnage correspond-il au mode SPI ?
  • SDA et SCL sont-ils réellement en drain ouvert ?
  • Les résistances de pull-up sont-elles présentes ?
  • La fréquence PWM et la résolution sont-elles adaptées ?
  • Les signaux start/busy/done ont-ils une durée claire ?
  • Les sorties sont-elles dans leur état de repos au reset ?

Erreurs fréquentes

Erreur

Conséquence

Correction

TX actif bas au reposUART illisibleRepos à 1
Bit UART MSB en premierOctet incorrectLSB en premier
Baud approximatif non vérifiéErreurs de trameCalculer l’erreur
Mauvais CPOL/CPHADécalage des bits SPIConfigurer le mode
I²C forcé à 1Conflit électriqueRelâcher en Z
Absence de pull-up I²CLigne flottante/basseRésistances adaptées
PWM vers moteur sans driverRisque matérielÉtage de puissance

 

Travaux pratiques

TP 16 — Interfaces et communications

1. Objectifs du TP

  • réaliser un générateur PWM 8 bits ;
  • faire varier la luminosité d’une LED ;
  • concevoir un émetteur UART 8N1 ;
  • transmettre la valeur d’un compteur vers un ordinateur ;
  • observer les trames avec un terminal ou analyseur logique ;
  • étudier une interface SPI mode 0 d’introduction.

2. Organisation du projet

Arborescence proposée  |  Arborescence
tp16_interfaces/
├── src/
│   ├── pwm_generique.vhd
│   ├── generateur_baud.vhd
│   ├── uart_tx.vhd
│   ├── emetteur_compteur.vhd
│   ├── spi_maitre_mode0.vhd
│   └── top_fpga.vhd
├── sim/
│   ├── tb_pwm.vhd
│   ├── tb_uart_tx.vhd
│   └── tb_spi_maitre.vhd
└── constraints/
    └── carte.xdc_ou_qsf

 

3. Partie A — Générateur PWM

Utiliser le composant pwm_generique de la section 20.5 avec N=8.

Connexion à une LED  |   VHDL
U_PWM : entity work.pwm_generique(rtl)
    generic map (
        N => 8
    )
    port map (
        clk   => clk_carte,
        reset => reset,
        duty  => unsigned(interrupteurs),
        pwm   => led_pwm
    );

 

4. Banc de test PWM

tb_pwm.vhd — Mesure du rapport  |  VHDL
-- Avec N=4 pour une simulation courte.
duty <= to_unsigned(4, 4);

compteur_haut := 0;

for i in 1 to 16 loop
    wait until rising_edge(clk);
    wait for 1 ns;

    if pwm = '1' then
        compteur_haut := compteur_haut + 1;
    end if;
end loop;

assert compteur_haut = 4
    report "Rapport cyclique incorrect"
    severity error;

 

5. Essais de luminosité

Interrupteurs

Duty

Observation

000000000/256LED éteinte
0100000064/256 ≈ 25 % 
10000000128/256 = 50 % 
11000000192/256 = 75 % 
11111111255/256Luminosité presque maximale

 

6. Partie B — Émetteur UART

Instancier generateur_baud et uart_tx. Choisir 115 200 bit/s ou un débit compatible avec le pont USB-UART de la carte.

7. Transmission d’un compteur

Le compteur binaire est converti en deux caractères hexadécimaux, suivis de CR et LF.

Valeur

Caractères transmis

000\r\n
100A\r\n
165A5\r\n
255FF\r\n

 

8. Conversion nibble vers ASCII

Fonction hexadécimale  |  VHDL
function hex_ascii(
    nibble : unsigned(3 downto 0)
) return std_logic_vector is
begin
    if nibble < 10 then
        return std_logic_vector(
            to_unsigned(48 + to_integer(nibble), 8)
        );
    else
        return std_logic_vector(
            to_unsigned(55 + to_integer(nibble), 8)
        );
    end if;
end function;

 

9. Séquence d’émission

Index

Octet

0Demi-octet fort en ASCII
1Demi-octet faible en ASCII
2CR = x0D
3LF = x0A

 

10. FSM d’émission du compteur

emetteur_compteur.vhd — Principe  |  Architecture
case etat is
    when ATTENTE =>
        if tick_envoi = '1' then
            valeur_capturee <= compteur;
            index_octet <= 0;
            etat <= PREPARER;
        end if;

    when PREPARER =>
        -- Sélectionner l'octet selon index_octet.
        etat <= LANCER;

    when LANCER =>
        if uart_busy = '0' then
            uart_start <= '1';
            etat <= ATTENDRE_FIN;
        end if;

    when ATTENDRE_FIN =>
        uart_start <= '0';

        if uart_done = '1' then
            if index_octet = 3 then
                etat <= ATTENTE;
            else
                index_octet <= index_octet + 1;
                etat <= PREPARER;
            end if;
        end if;
end case;

 

11. Banc de test UART

Vérification d’une trame xA5  |  VHDL
constant OCTET_TEST : std_logic_vector(7 downto 0) := x"A5";

data_in <= OCTET_TEST;
start <= '1';
wait until rising_edge(clk);
start <= '0';

-- START.
wait until baud_tick = '1';
assert tx = '0' severity error;

-- Bits LSB en premier : 1,0,1,0,0,1,0,1.
for i in 0 to 7 loop
    wait until baud_tick = '1';

    assert tx = OCTET_TEST(i)
        report "Bit UART incorrect"
        severity error;
end loop;

-- STOP.
wait until baud_tick = '1';
assert tx = '1' severity error;

 

Simulation — Chronologie du banc de test

Selon l’instant exact du start et la manière dont le tick est généré, le test doit échantillonner au milieu de chaque cellule ou utiliser un tick de simulation contrôlé. Il faut éviter une vérification ambiguë sur le même front que la mise à jour de TX.

 

12. Connexion au PC

1. Identifier la broche TX du FPGA et la tension logique.

2. Utiliser un pont USB-UART compatible.

3. Relier les masses.

4. Relier TX FPGA à RX du pont.

5. Configurer le terminal : débit choisi, 8N1, pas de contrôle de flux.

6. Programmer la carte.

7. Observer les lignes hexadécimales.

13. Contraintes conceptuelles

Exemple XDC  |   Contraintes
set_property PACKAGE_PIN <PIN_TX> [get_ports uart_tx]
set_property IOSTANDARD LVCMOS33 [get_ports uart_tx]

set_property PACKAGE_PIN <PIN_LED> [get_ports led_pwm]
set_property IOSTANDARD LVCMOS33 [get_ports led_pwm]

create_clock -period 20.000   -name clk_carte   [get_ports clk_carte]

 

14. Partie C — Introduction SPI

Réaliser une transaction mode 0 de huit bits, avec un esclave de test qui renvoie un motif.

Esclave de test conceptuel  |  Principe
-- À chaque front montant SCLK :
registre_rx <= registre_rx(6 downto 0) & mosi;

-- MISO présente le bit de poids fort
-- du registre de réponse.

 

15. Vérifications SPI

  • SCLK reste bas au repos ;
  • CS_n passe à 0 avant le transfert ;
  • MOSI présente le MSB en premier ;
  • MISO est échantillonné sur les fronts montants ;
  • huit bits sont transférés ;
  • CS_n revient à 1 ;
  • done dure un cycle.

16. Commandes GHDL

Compilation  |   Terminal
ghdl -a --std=08 src/pwm_generique.vhd
ghdl -a --std=08 src/generateur_baud.vhd
ghdl -a --std=08 src/uart_tx.vhd
ghdl -a --std=08 src/emetteur_compteur.vhd
ghdl -a --std=08 src/spi_maitre_mode0.vhd

 

Simulation UART  |   Terminal
ghdl -a --std=08 sim/tb_uart_tx.vhd
ghdl -e --std=08 tb_uart_tx
ghdl -r --std=08 tb_uart_tx    --vcd=tb_uart_tx.vcd

gtkwave tb_uart_tx.vcd

 

17. Signaux à observer

Bloc

Signaux

PWMphase, duty, pwm
UARTbaud_tick, start, tx, busy, done, registre, index_bit
SPIcs_n, sclk, mosi, miso, compteur_bits, busy, done

 

18. Tableau de résultats

Test

Attendu

Observé

Conforme

PWM duty=25 %4 cycles hauts sur 16 en simulation  
PWM LEDLuminosité variable  
UART xA5START + 8 bits + STOP  
UART vers PCValeur hexadécimale lisible  
SPI mode 08 bits échangés  
Rapport de synthèseCompteurs, registres et FSM attendus  

 

19. Questions d’analyse

1. Quelle différence existe entre communication parallèle et série ?

2. Pourquoi une trame UART 8N1 contient-elle dix bits ?

3. Pourquoi l’UART transmet-il le LSB en premier ?

4. Comment calculer le diviseur du générateur de baud ?

5. Quel est le rôle de busy et done dans l’émetteur ?

6. Pourquoi un récepteur UART suréchantillonne-t-il la ligne ?

7. Quelle différence existe entre CPOL et CPHA ?

8. Pourquoi SPI est-il full-duplex ?

9. Pourquoi I²C ne doit-il pas forcer SDA à 1 ?

10. Comment le rapport cyclique agit-il sur une LED ?

20. Extensions proposées

  • Ajouter une parité paire à l’UART.
  • Concevoir un récepteur UART ×16.
  • Ajouter une FIFO TX.
  • Transmettre un nombre décimal plutôt qu’hexadécimal.
  • Compléter le maître SPI mode 0.
  • Ajouter les modes SPI 1, 2 et 3.
  • Créer un contrôleur I²C d’écriture d’un octet.
  • Ajouter une correction gamma au PWM.
  • Commander un servomoteur avec une PWM adaptée.

21. Barème indicatif

Critère

Points

Générateur PWM3
Commande de luminosité2
Générateur de baud3
Émetteur UART4
Transmission vers le PC3
Introduction SPI2
Bancs de test et chronogrammes2
Qualité du compte rendu1
Total20

 

Synthèse du chapitre

Notion

Résumé

Communication sérieTransmission successive des bits.
UARTInterface asynchrone à TX/RX.
8N18 données, aucune parité, 1 stop.
Baud tickImpulsion définissant la durée d’un bit.
SPIBus synchrone full-duplex avec SCLK et CS.
CPOL/CPHAPolarité et phase de l’horloge SPI.
I²CBus adressé à SDA/SCL.
Drain ouvertLes participants forcent 0 ou relâchent la ligne.
ACKAcquittement au neuvième bit I²C.
PWMCommande par rapport cyclique.
Résolution PWMNombre de niveaux de duty.
Étage de puissanceInterface obligatoire pour un moteur.

 

Autoévaluation

1. Quelle est la ligne UART au repos ?

Réponse : Le niveau haut.

2. Que signifie 8N1 ?

Réponse : 8 bits, sans parité, un stop.

3. Dans quel ordre partent les bits UART ?

Réponse : LSB en premier.

4. Qui produit SCLK en SPI ?

Réponse : Le maître.

5. Que définissent CPOL et CPHA ?

Réponse : Le niveau de repos et les fronts SPI.

6. Combien de fils principaux utilise I²C ?

Réponse : Deux : SDA et SCL.

7. Comment un participant I²C produit-il un 1 ?

Réponse : Il relâche la ligne.

8. Que signifie ACK ?

Réponse : Le récepteur tire SDA à zéro au neuvième bit.

9. Que contrôle le duty d’une PWM ?

Réponse : La proportion de temps au niveau haut.

10. Peut-on connecter un moteur au FPGA ?

Réponse : Non, un driver de puissance est nécessaire.

Exercice de consolidation

Pour une horloge de 100 MHz, calculer le diviseur entier d’un UART à 9 600 bit/s et la fréquence d’une PWM 10 bits sans prescaler.

Correction proposée  |  Calcul
UART :
DIVISEUR ≈ 100000000 / 9600
          ≈ 10416,67

Choix arrondi : 10417
Baud obtenu ≈ 100000000 / 10417
            ≈ 9599,69 bit/s

PWM 10 bits :
F_PWM = 100 MHz / 1024
      ≈ 97,65625 kHz

 

Suite du cours — Transition vers la suite

Après les interfaces numériques, le cours peut aborder les bonnes pratiques d’architecture, de réutilisation, de documentation, de vérification et de gestion de projet VHDL.