Construire votre premier FPGA : tutoriel LED clignotante (VHDL & Verilog)
Introduction
Bienvenue dans ce guide pratique qui vous accompagne dans la création d'un simple clignotement de LED sur FPGA en VHDL ou Verilog. L'exemple démontre les concepts fondamentaux FPGA : processus concurrents, synthèse de fréquence, et logique multiplexeur — le tout piloté par une horloge 25 MHz.
Vue d'ensemble du projet
- Générer quatre fréquences de clignotement sélectionnables : 100 Hz, 50 Hz, 10 Hz et 1 Hz.
- Maintenir un cycle de travail de 50 % pour chaque fréquence.
- Activer la LED seulement quand le commutateur
LED_ENest actif. - Choisir la fréquence désirée via deux commutateurs indépendants.
- La simulation est requise avant le déploiement matériel pour détecter les erreurs tôt.
Table de vérité de sélection de fréquence
| Enable | Switch 1 | Switch 2 | Fréquence pilotage LED |
|---|---|---|---|
| 0 | - | - | (désactivé) |
| 1 | 0 | 0 | 100 Hz |
| 1 | 0 | 1 | 50 Hz |
| 1 | 1 | 0 | 10 Hz |
| 1 | 1 | 1 | 1 Hz |
Définitions des signaux
| Nom du signal | Direction | Description |
|---|---|---|
| i_clock | Entrée | Horloge système 25 MHz |
| i_enable | Entrée | Commutateur activation LED (logique 0 = éteint) |
| i_switch_1 | Entrée | Sélecteur fréquence bit 1 |
| i_switch_2 | Entrée | Sélecteur fréquence bit 0 |
| o_led_drive | Sortie | Signal de pilotage pour la LED |
Philosophie de conception
Quatre processus de compteur indépendants s'exécutent en parallèle, chacun basculant un signal local à sa fréquence cible. Même quand une fréquence particulière n'est pas sélectionnée, son compteur continue de tourner — c'est la marque de la concurrence FPGA.
Les commutateurs implémentent un multiplexeur combinatoire qui route le signal de basculement désiré vers le pilote LED. Le commutateur LED_EN agit comme une porte active-haute, assurant que la LED s'éteint quand l'activation est basse.
Diagramme de blocs
Implémentation VHDL
Ci-dessous un module VHDL entièrement commenté satisfaisant la spécification. Les constantes de compteur sont calculées avec la formule :
count = (fréquence horloge / fréquence cible) × 0.5 pour obtenir un cycle de travail de 50 %.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity tutorial_led_blink is port ( i_clock : in std_logic; i_enable : in std_logic; i_switch_1 : in std_logic; i_switch_2 : in std_logic; o_led_drive : out std_logic ); end tutorial_led_blink; architecture rtl of tutorial_led_blink is -- Constantes de fréquence (comptages demi-période) constant c_CNT_100HZ : natural := 125000; -- 25 MHz / 100 Hz × 0.5 constant c_CNT_50HZ : natural := 250000; -- 25 MHz / 50 Hz × 0.5 constant c_CNT_10HZ : natural := 1250000; -- 25 MHz / 10 Hz × 0.5 constant c_CNT_1HZ : natural := 12500000; -- 25 MHz / 1 Hz × 0.5 -- Signaux compteurs signal r_CNT_100HZ : natural range 0 to c_CNT_100HZ; signal r_CNT_50HZ : natural range 0 to c_CNT_50HZ; signal r_CNT_10HZ : natural range 0 to c_CNT_10HZ; signal r_CNT_1HZ : natural range 0 to c_CNT_1HZ; -- Sorties de basculement signal r_TOGGLE_100HZ : std_logic := '0'; signal r_TOGGLE_50HZ : std_logic := '0'; signal r_TOGGLE_10HZ : std_logic := '0'; signal r_TOGGLE_1HZ : std_logic := '0'; -- Sélection multiplexeur signal w_LED_SELECT : std_logic; begin -- Processus basculement 100 Hz p_100_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_100HZ = c_CNT_100HZ-1 then r_TOGGLE_100HZ <= not r_TOGGLE_100HZ; r_CNT_100HZ <= 0; else r_CNT_100HZ <= r_CNT_100HZ + 1; end if; end if; end process p_100_HZ; -- Processus basculement 50 Hz p_50_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_50HZ = c_CNT_50HZ-1 then r_TOGGLE_50HZ <= not r_TOGGLE_50HZ; r_CNT_50HZ <= 0; else r_CNT_50HZ <= r_CNT_50HZ + 1; end if; end if; end process p_50_HZ; -- Processus basculement 10 Hz p_10_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_10HZ = c_CNT_10HZ-1 then r_TOGGLE_10HZ <= not r_TOGGLE_10HZ; r_CNT_10HZ <= 0; else r_CNT_10HZ <= r_CNT_10HZ + 1; end if; end if; end process p_10_HZ; -- Processus basculement 1 Hz p_1_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_1HZ = c_CNT_1HZ-1 then r_TOGGLE_1HZ <= not r_TOGGLE_1HZ; r_CNT_1HZ <= 0; else r_CNT_1HZ <= r_CNT_1HZ + 1; end if; end if; end process p_1_HZ; -- Multiplexeur basé sur les entrées commutateurs w_LED_SELECT <= r_TOGGLE_100HZ when (i_switch_1 = '0' and i_switch_2 = '0') else r_TOGGLE_50HZ when (i_switch_1 = '0' and i_switch_2 = '1') else r_TOGGLE_10HZ when (i_switch_1 = '1' and i_switch_2 = '0') else r_TOGGLE_1HZ; -- Pilotage LED avec porte d'activation o_led_drive <= w_LED_SELECT and i_enable; end rtl;
Implémentation Verilog
Ci-dessous un module Verilog équivalent. La philosophie de conception est identique — quatre blocs always indépendants, chacun basculant à une fréquence spécifique, et un multiplexeur combinatoire piloté par les commutateurs.
module tutorial_led_blink ( i_clock, i_enable, i_switch_1, i_switch_2, o_led_drive ); input i_clock; input i_enable; input i_switch_1; input i_switch_2; output o_led_drive; // Paramètres de fréquence (comptages demi-période) parameter c_CNT_100HZ = 125000; parameter c_CNT_50HZ = 250000; parameter c_CNT_10HZ = 1250000; parameter c_CNT_1HZ = 12500000; // Registres compteurs reg [31:0] r_CNT_100HZ = 0; reg [31:0] r_CNT_50HZ = 0; reg [31:0] r_CNT_10HZ = 0; reg [31:0] r_CNT_1HZ = 0; // Registres basculement reg r_TOGGLE_100HZ = 1'b0; reg r_TOGGLE_50HZ = 1'b0; reg r_TOGGLE_10HZ = 1'b0; reg r_TOGGLE_1HZ = 1'b0; // Sélection multiplexeur reg r_LED_SELECT; wire w_LED_SELECT; // Bloc basculement 100 Hz always @(posedge i_clock) begin if (r_CNT_100HZ == c_CNT_100HZ-1) begin r_TOGGLE_100HZ <= ~r_TOGGLE_100HZ; r_CNT_100HZ <= 0; end else r_CNT_100HZ <= r_CNT_100HZ + 1; end // Bloc basculement 50 Hz always @(posedge i_clock) begin if (r_CNT_50HZ == c_CNT_50HZ-1) begin r_TOGGLE_50HZ <= ~r_TOGGLE_50HZ; r_CNT_50HZ <= 0; end else r_CNT_50HZ <= r_CNT_50HZ + 1; end // Bloc basculement 10 Hz always @(posedge i_clock) begin if (r_CNT_10HZ == c_CNT_10HZ-1) begin r_TOGGLE_10HZ <= ~r_TOGGLE_10HZ; r_CNT_10HZ <= 0; end else r_CNT_10HZ <= r_CNT_10HZ + 1; end // Bloc basculement 1 Hz always @(posedge i_clock) begin if (r_CNT_1HZ == c_CNT_1HZ-1) begin r_TOGGLE_1HZ <= ~r_TOGGLE_1HZ; r_CNT_1HZ <= 0; end else r_CNT_1HZ <= r_CNT_1HZ + 1; end // Multiplexeur combinatoire always @(*) begin case ({i_switch_1, i_switch_2}) 2'b11: r_LED_SELECT <= r_TOGGLE_1HZ; 2'b10: r_LED_SELECT <= r_TOGGLE_10HZ; 2'b01: r_LED_SELECT <= r_TOGGLE_50HZ; 2'b00: r_LED_SELECT <= r_TOGGLE_100HZ; endcase end // Pilotage LED avec porte d'activation assign o_led_drive = r_LED_SELECT & i_enable; endmodule
Simulation et vérification
Avant de programmer le FPGA, lancez une simulation comportementale (ex: ModelSim, VCS, ou Vivado Simulator). Vérifiez que chaque signal de basculement correspond à la période attendue et que le multiplexeur route correctement le signal selon la combinaison des commutateurs. La simulation précoce élimine le débogage matériel coûteux et confirme que le cycle de travail de 50 % est maintenu.
Conclusion
Ce tutoriel montre comment construire un clignoteur LED compact et réutilisable adaptable à d'autres tâches de temporisation. Le même motif de synthèse de fréquence basé sur compteurs s'étend à des machines d'état plus complexes, en faisant une compétence fondamentale pour tout développeur FPGA.
VHDL
- C# Hello World — Construire votre première application C#
- Démarrer avec le développement FPGA : Construction d'un additionneur 4 bits sur Xilinx Artix‑7
- La technologie eFPGA : révolutionner la conception ASIC et SoC
- Optimisez votre programme d'analyse de lubrifiants pour une fiabilité maximale des actifs
- Maîtriser Verilog : Tutoriel complet pour la conception de circuits numériques
- Concevoir un Programme de Maintenance Préventive Efficace pour l'Équipement
- 10 Stratégies Prouvées pour Améliorer Votre Programme de Maintenance Préventive
- Maîtriser rapidement la conception PCB avec Ultiboard : Tutoriel complet
- Tutoriel KiCad PCB : Maîtriser le développement PCB open-source