Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> VHDL

Comment construire votre premier clignotant LED FPGA : Tutoriel pas à pas

Guide pas à pas : Construction de votre premier clignotant LED FPGA

Partie 1 : Conception VHDL ou Verilog

Dans ce tutoriel, vous apprendrez à écrire du code VHDL et Verilog qui fait clignoter une LED à une fréquence définie par l'utilisateur. Choisissez le langage qui convient le mieux à votre flux de travail.

Lors de l'écriture en HDL, vous devez vérifier que le design se comporte comme prévu. Les erreurs sont inévitables, donc la simulation est indispensable. Ce tutoriel est divisé en deux phases critiques :

  1. Conception HDL
  2. Simulation HDL

Sauter la simulation peut mener à un débogage matériel coûteux. Traitez la simulation comme un point de contrôle obligatoire.

Exigences du projet

Écrivez du HDL qui fait clignoter une LED à 100 Hz, 50 Hz, 10 Hz ou 1 Hz avec un cycle de service de 50 %. Deux interrupteurs sélectionnent la fréquence désirée, et un interrupteur LED_EN supplémentaire doit être à l'état haut pour activer la LED. Le FPGA fonctionne sur un oscillateur de 25 MHz.

Table de vérité pour le sélecteur de fréquence :

ActiverInterrupteur 1Interrupteur 2Fréquence LED
0––désactivé
100100 Hz
10150 Hz
11010 Hz
1111 Hz

Résumé des signaux :

Nom du signalDirectionDescription
i_clockEntréeHorloge 25 MHz
i_enableEntréeInterrupteur d'activation (logique 0 = LED éteinte)
i_switch_1EntréeInterrupteur sélecteur de fréquence 1
i_switch_2EntréeInterrupteur sélecteur de fréquence 2
o_led_driveSortieSignal de commande LED

Quatre processus de compteur concurrents surveillent l'horloge 25 MHz et génèrent des basculements pour chaque fréquence cible. Même lorsqu'une fréquence particulière n'est pas sélectionnée, son compteur continue de s'exécuter – un principe fondamental de la concurrence matérielle.

Les interrupteurs forment un multiplexeur qui route le basculement choisi vers la sortie LED. Les multiplexeurs sont une logique purement combinatoire, ils fonctionnent donc sans horloge.

Ci-dessous, un diagramme de blocs illustrant l'architecture :

Comment construire votre premier clignotant LED FPGA : Tutoriel pas à pas

Implémentation VHDL

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 pour créer les fréquences nécessaires :
-- Formule : (25 MHz / 100 Hz * 50% duty cycle)
-- Pour 100 Hz : 25,000,000 / 100 * 0.5 = 125,000
constant c_CNT_100HZ : natural := 125000;
constant c_CNT_50HZ : natural := 250000;
constant c_CNT_10HZ : natural := 1250000;
constant c_CNT_1HZ : natural := 12500000;

-- Ces signaux seront les 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;

-- Ces signaux basculeront aux fréquences nécessaires :
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';

-- Fil de sélection d'un bit.
signal w_LED_SELECT : std_logic;

begin
-- Tous les processus basculent un signal spécifique à une fréquence différente.
-- Ils s'exécutent tous continuellement même si les interrupteurs
-- ne sélectionnent pas leur sortie particulière.
p_100_HZ : process (i_clock) is
begin
    if rising_edge(i_clock) then
        if r_CNT_100HZ = c_CNT_100HZ-1 then
            -- -1, car le compteur commence à 0
            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;

p_50_HZ : process (i_clock) is
begin
    if rising_edge(i_clock) then
        if r_CNT_50HZ = c_CNT_50HZ-1 then
            -- -1, car le compteur commence à 0
            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;

p_10_HZ : process (i_clock) is
begin
    if rising_edge(i_clock) then
        if r_CNT_10HZ = c_CNT_10HZ-1 then
            -- -1, car le compteur commence à 0
            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;

p_1_HZ : process (i_clock) is
begin
    if rising_edge(i_clock) then
        if r_CNT_1HZ = c_CNT_1HZ-1 then
            -- -1, car le compteur commence à 0
            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;

-- Créer un multiplexeur basé sur les entrées d'interrupteurs
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;

-- N'autoriser o_led_drive à piloter que lorsque i_enable est haut (porte ET).
o_led_drive <= w_LED_SELECT and i_enable;
end rtl;

Implémentation Verilog

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;

// Constantes (paramètres) pour créer les fréquences nécessaires :
// Horloge d'entrée 25 kHz, choisie arbitrairement.
// Formule : (25 kHz / 100 Hz * 50% duty cycle)
// Pour 100 Hz : 25,000 / 100 * 0.5 = 125
parameter c_CNT_100HZ = 125;
parameter c_CNT_50HZ = 250;
parameter c_CNT_10HZ = 1250;
parameter c_CNT_1HZ = 12500;

// Ces signaux seront les 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;

// Ces signaux basculeront aux fréquences nécessaires :
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 d'un bit
reg r_LED_SELECT;
wire w_LED_SELECT;

begin
// Tous les blocs always basculent un signal spécifique à une fréquence différente.
// Ils s'exécutent tous continuellement même si les interrupteurs
-- ne sélectionnent pas leur sortie particulière.
always @ (posedge i_clock) begin
    if (r_CNT_100HZ == c_CNT_100HZ-1) // -1, car le compteur commence à 0
    begin
        r_TOGGLE_100HZ <= !r_TOGGLE_100HZ;
        r_CNT_100HZ <= 0;
    end else
        r_CNT_100HZ <= r_CNT_100HZ + 1;
end

always @ (posedge i_clock) begin
    if (r_CNT_50HZ == c_CNT_50HZ-1) // -1, car le compteur commence à 0
    begin
        r_TOGGLE_50HZ <= !r_TOGGLE_50HZ;
        r_CNT_50HZ <= 0;
    end else
        r_CNT_50HZ <= r_CNT_50HZ + 1;
end

always @ (posedge i_clock) begin
    if (r_CNT_10HZ == c_CNT_10HZ-1) // -1, car le compteur commence à 0
    begin
        r_TOGGLE_10HZ <= !r_TOGGLE_10HZ;
        r_CNT_10HZ <= 0;
    end else
        r_CNT_10HZ <= r_CNT_10HZ + 1;
end

always @ (posedge i_clock) begin
    if (r_CNT_1HZ == c_CNT_1HZ-1) // -1, car le compteur commence à 0
    begin
        r_TOGGLE_1HZ <= !r_TOGGLE_1HZ;
        r_CNT_1HZ <= 0;
    end else
        r_CNT_1HZ <= r_CNT_1HZ + 1;
end

// Créer un multiplexeur basé sur les entrées d'interrupteurs
always @ (*) begin
    case ({i_switch_1, i_switch_2}) // Opérateur de concaténation
        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

assign o_led_drive = r_LED_SELECT & i_enable;

// Méthode alternative pour concevoir le multiplexeur (identique à ci-dessus) :
// Plus compacte, mais plus difficile à lire, surtout pour les débutants en Verilog
// assign w_LED_SELECT = i_switch_1 ? (i_switch_2 ? r_TOGGLE_1HZ : r_TOGGLE_10HZ) :
//(i_switch_2 ? r_TOGGLE_50HZ : r_TOGGLE_100HZ);
// assign o_led_drive = w_LED_SELECT & i_enable;
end
endmodule

Étape suivante : Simulez ce design en VHDL ou Verilog pour confirmer le comportement correct avant le déploiement.

VHDL

  1. Implémentation d'une liste chainée dynamique en VHDL avec types protégés et pointeurs d'accès
  2. Implémenter un contrôleur PWM en VHDL : Conception, simulation et démo FPGA
  3. Maîtriser l'instanciation par port map en VHDL : Guide pratique
  4. Implémenter une FIFO AXI en RAM bloc avec handshake Ready/Valid
  5. Créer un effet LED respirant avec une onde sinusoïdale depuis la RAM bloc
  6. Construction d'un processus déclenché par horloge en VHDL : Guide pratique
  7. Quiz VHDL Avancé - Partie 3 : Testez votre expertise HDL
  8. Utilisation des procédures en VHDL : Simplifiez votre design avec du code réutilisable
  9. Comment construire un testbench auto-vérifiant en VHDL - Guide pratique