Uw Eerste FPGA Bouwen: LED Knipper Tutorial (VHDL & Verilog)
Inleiding
Welkom bij een hands-on gids die u doorloopt bij het creëren van een eenvoudige LED-knipper op een FPGA met behulp van VHDL of Verilog. Het voorbeeld demonstreert kern FPGA-concepten: concurrente processen, frequentiesynthese, en multiplexer-logica – allemaal aangedreven door een 25 MHz klok.
Projectoverzicht
- Genereer vier selecteerbare knipperfrequenties: 100 Hz, 50 Hz, 10 Hz, en 1 Hz.
- Handhaaf een 50% duty cycle voor elke frequentie.
- Schakel de LED alleen in wanneer een
LED_ENschakelaar geactiveerd is. - Kies de gewenste frequentie via twee onafhankelijke schakelaars.
- Simulatie is vereist voordat u naar hardware deployed om fouten vroegtijdig te vangen.
Frequentie-selectie Waarheidstabel
| Enable | Schakelaar 1 | Schakelaar 2 | LED Drive Frequentie |
|---|---|---|---|
| 0 | - | - | (uitgeschakeld) |
| 1 | 0 | 0 | 100 Hz |
| 1 | 0 | 1 | 50 Hz |
| 1 | 1 | 0 | 10 Hz |
| 1 | 1 | 1 | 1 Hz |
Signaaldefinities
| Signaalnaam | Richting | Beschrijving |
|---|---|---|
| i_clock | Input | 25 MHz systeemklok |
| i_enable | Input | LED enable schakelaar (logica 0 = uit) |
| i_switch_1 | Input | Frequentie selector bit 1 |
| i_switch_2 | Input | Frequentie selector bit 0 |
| o_led_drive | Output | Drive signaal voor de LED |
Ontwervolosofie
Vier onafhankelijke tellerprocessen draaien concurrents, elk een lokaal signaal omkerend op de doelfrequentie. Zelfs wanneer een bepaalde frequentie niet geselecteerd is, blijft de teller draaien – dit is de kenmerk van FPGA-concurrentie.
De schakelaars implementeren een combinatoire multiplexer die het gewenste toggle-signaal routeert naar de LED-driver. De LED_EN schakelaar fungeert als actieve-hoog gate, wat zorgt dat de LED uigaat wanneer de enable laag is.
Blokdiagram
VHDL Implementatie
Hieronder staat een volledig gecommentarieerde VHDL-module die aan de specificatie voldoet. De tellerconstanten zijn berekend met de formule:
count = (klokfrequentie / doelfrequentie) × 0.5 om een 50% duty cycle te bereiken.
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 -- Frequentie constanten (half-periode tellingen) 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 -- Teller signalen 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; -- Toggle outputs 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'; -- Multiplexer selectie signal w_LED_SELECT : std_logic; begin -- 100 Hz toggle process 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; -- 50 Hz toggle process 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; -- 10 Hz toggle process 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; -- 1 Hz toggle process 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; -- Multiplexer gebaseerd op schakelaarinputs 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; -- Gate de LED drive met de enable schakelaar o_led_drive <= w_LED_SELECT and i_enable; end rtl;
Verilog Implementatie
Hieronder staat een equivalente Verilog-module. De ontwervolosofie is identiek – vier onafhankelijke always blokken, elk toggelend op een specifieke frequentie, en een combinatoire multiplexer aangedreven door de schakelaars.
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; // Frequentie parameters (half-periode tellingen) parameter c_CNT_100HZ = 125000; parameter c_CNT_50HZ = 250000; parameter c_CNT_10HZ = 1250000; parameter c_CNT_1HZ = 12500000; // Teller registers 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; // Toggle registers reg r_TOGGLE_100HZ = 1'b0; reg r_TOGGLE_50HZ = 1'b0; reg r_TOGGLE_10HZ = 1'b0; reg r_TOGGLE_1HZ = 1'b0; // Multiplexer selectie reg r_LED_SELECT; wire w_LED_SELECT; // 100 Hz toggle blok 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 // 50 Hz toggle blok 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 // 10 Hz toggle blok 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 // 1 Hz toggle blok 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 // Combinatoire multiplexer 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 // Drive LED met enable gating assign o_led_drive = r_LED_SELECT & i_enable; endmodule
Simulatie & Verificatie
Voordat u de FPGA programmeert, voer een behavioral simulatie uit (bijv. met ModelSim, VCS, of Vivado Simulator). Verifieer dat elk toggle-signaal de verwachte periode matcht en dat de multiplexer correct routeert gebaseerd op de schakelaarcombinatie. Vroeg simuleren elimineert dure hardware-debugging en bevestigt dat de 50% duty cycle gehandhaafd blijft.
Conclusie
Deze tutorial demonstreert hoe een compacte, herbruikbare LED-knipper te bouwen die aangepast kan worden aan andere timing-taken. Hetzelfde teller-gebaseerde frequentiesynthesepatroon schaalt naar complexere state machines, wat het een fundamentele vaardigheid maakt voor elke FPGA-ontwikkelaar.
VHDL
- Preventief Onderhoud Meesteren: Strategieën om uw PM-programma te Optimaliseren
- Verbeter uw smeringanalyseprogramma voor piek activabetrouwbaarheid
- 10 bewezen strategieën om uw preventief onderhoudsprogramma te verbeteren
- PCB-ontwerp snel beheersen met Ultiboard: Een uitgebreide tutorial
- KiCad PCB-ontwerp tutorial: Open-source PCB-ontwikkeling beheersen
- Een Effectief Preventief Onderhoudsprogramma Ontwerpen Voor Apparatuur
- Aan de slag met FPGA-ontwikkeling: Een 4-bit-adder bouwen op Xilinx Artix‑7
- Embedded FPGA (eFPGA) technologie: ASIC en SoC ontwerp revolutionerend
- C# Hello World – Uw eerste C# applicatie bouwen
- Je eerste VHDL-programma: Stap-voor-stap Hello World tutorial
- Verilog beheersen: Complete tutorial voor digitale schakelingontwerp