初めてのFPGA:LED点滅チュートリアル(VHDL&Verilog)
はじめに
VHDLまたはVerilogを使って、FPGA上でシンプルなLED点滅器を作る実践ガイドへようこそ。この例は、コンカレント プロセス、周波数合成、マルチプレクサ ロジックなど、25MHzクロックで駆動されるFPGAの核心概念を示します。
プロジェクト概要
- 4つの選択可能な点滅周波数を生成:100Hz、50Hz、10Hz、1Hz
- 各周波数で50%デューティ サイクルを維持
LED_ENスイッチがアサートされているときのみLEDを有効化- 2つの独立したスイッチで希望の周波数を選択
- ハードウェア展開前にシミュレーション必須、早期にエラーを検出
周波数選択真理値表
| Enable | Switch 1 | Switch 2 | LED駆動周波数 |
|---|---|---|---|
| 0 | - | - | (無効) |
| 1 | 0 | 0 | 100 Hz |
| 1 | 0 | 1 | 50 Hz |
| 1 | 1 | 0 | 10 Hz |
| 1 | 1 | 1 | 1 Hz |
信号定義
| 信号名 | 方向 | 説明 |
|---|---|---|
| i_clock | 入力 | 25 MHz システム クロック |
| i_enable | 入力 | LEDイネーブル スイッチ (ロジック0=オフ) |
| i_switch_1 | 入力 | 周波数セレクタ ビット1 |
| i_switch_2 | 入力 | 周波数セレクタ ビット0 |
| o_led_drive | 出力 | LED駆動信号 |
設計思想
4つの独立したカウンタ プロセスが並行して動作し、それぞれ目標周波数でローカル信号をトグルします。特定の周波数が選択されていないときも、そのカウンタは動き続けます。これがFPGAの並行性の特徴です。
スイッチは組み合わせマルチプレクサを実装し、目的のトグル信号をLEDドライバーにルーティングします。LED_ENスイッチはアクティブハイ ゲートとして働き、イネーブルがLowのときLEDを消灯させます。
ブロック図
VHDL実装
以下は仕様を満たす完全コメント付きVHDLモジュールです。カウンタ定数は以下の式で計算:
count = (クロック周波数 / 目標周波数) × 0.5 で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 -- 周波数定数(半周期カウント) 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 -- カウンタ信号 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; -- トグル出力 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'; -- マルチプレクサ選択 signal w_LED_SELECT : std_logic; begin -- 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; -- 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; -- 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; -- 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; -- スイッチ入力に基づくマルチプレクサ 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; -- イネーブル スイッチでLED駆動をゲート o_led_drive <= w_LED_SELECT and i_enable; end rtl;
Verilog実装
以下は同等のVerilogモジュールです。設計思想は同一—4つの独立したalwaysブロックが各周波数でトグルし、スイッチ駆動の組み合わせマルチプレクサで選択します。
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; // 周波数パラメータ(半周期カウント) parameter c_CNT_100HZ = 125000; parameter c_CNT_50HZ = 250000; parameter c_CNT_10HZ = 1250000; parameter c_CNT_1HZ = 12500000; // カウンタ レジスタ 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; // トグル レジスタ reg r_TOGGLE_100HZ = 1'b0; reg r_TOGGLE_50HZ = 1'b0; reg r_TOGGLE_10HZ = 1'b0; reg r_TOGGLE_1HZ = 1'b0; // マルチプレクサ選択 reg r_LED_SELECT; wire w_LED_SELECT; // 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 // 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 // 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 // 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 // 組み合わせマルチプレクサ 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 // イネーブル ゲートでLED駆動 assign o_led_drive = r_LED_SELECT & i_enable; endmodule
シミュレーションと検証
FPGAにプログラミングする前に、振る舞いシミュレーション(ModelSim、VCS、Vivado Simulatorなど)を実行してください。各トグル信号が期待周期と一致し、マルチプレクサがスイッチ組み合わせに基づいて正しく信号をルーティングすることを確認。早期シミュレーションで高コストなハードウェア デバッグを防ぎ、50%デューティ サイクルの維持を確認できます。
結論
このチュートリアルは、他のタイミング タスクに応用可能なコンパクトで再利用可能なLED点滅器の構築方法を示しました。同じカウンタベースの周波数合成パターンは、より複雑なステート マシンにも拡張可能で、あらゆるFPGA開発者の基礎スキルとなります。
VHDL
- 予防保全のマスター:PMプログラムを最適化する戦略
- 潤滑油分析プログラムを強化し、資産信頼性をピークに導く
- 予防保全プログラムを劇的に改善する10の実証済み戦略
- UltiboardでPCB設計をマスター:包括的チュートリアル
- KiCAD PCB設計チュートリアル:オープンソースPCB開発をマスターする
- 機器のための効果的な予防保全プログラム設計
- FPGA開発入門: Xilinx Artix-7で4ビットアダーを構築
- 組み込みFPGA(eFPGA)技術:ASIC/SoC設計に革命をもたらす
- C# Hello World – 初めてのC#アプリケーション構築
- 初めてのVHDLプログラム:ステップバイステップ Hello World チュートリアル
- Verilogマスター:デジタル回路設計のための完全チュートリアル