工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> VHDL

FPGAでLED点滅を作る:ステップバイステップチュートリアル

ステップバイステップガイド:初めてのFPGA LED点滅設計

パート1:VHDLまたはVerilogでの設計

このチュートリアルでは、ユーザー定義の周波数でLEDを駆動するVHDLおよびVerilogコードの作り方を学びます。ワークフローに合った言語を選んでください。

HDLを書く際は、設計が意図通りに振る舞うか検証する必要があります。間違いは避けられないため、シミュレーションは不可欠です。本チュートリアルは以下の2つの重要なフェーズで構成されます:

  1. HDL設計
  2. HDLシミュレーション

シミュレーションを省くと、実機デバッグで多大なコストがかかります。シミュレーションを必須のチェックポイントとして扱いましょう。

プロジェクト要件

100Hz、50Hz、10Hz、1Hzのいずれかで、デューティサイクル50%でLEDを点滅させるHDLを作成します。2つのスイッチで周波数を選択し、追加のLED_ENスイッチがHighのときのみLEDを有効化します。FPGAは25MHzの発振器で動作します。

周波数セレクタの真理値表:

EnableSwitch 1Switch 2LED駆動周波数
0––無効
100100 Hz
10150 Hz
11010 Hz
1111 Hz

信号まとめ:

信号名方向説明
i_clockInput25 MHzクロック
i_enableInputイネーブルスイッチ(ロジック0=LEDオフ)
i_switch_1Input周波数選択スイッチ1
i_switch_2Input周波数選択スイッチ2
o_led_driveOutputLED駆動信号

4つの並行カウンタプロセスが25MHzクロックを監視し、各目標周波数用のトグル信号を生成します。特定の周波数が選択されていないときも、そのカウンタは動き続けます。これはハードウェア並行性の核心原理です。

スイッチが多重化器(マルチプレクサ)を形成し、選択されたトグルをLED出力にルーティングします。マルチプレクサは純粋な組み合わせ論理なので、クロックなしで動作します。

以下はアーキテクチャを示すブロック図です:

FPGAでLED点滅を作る:ステップバイステップチュートリアル

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
    -- 周波数生成用定数
    -- 式: (25 MHz / 目標Hz * 50% duty)
    -- 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;

    -- カウンタ信号
    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';

    -- 1ビット選択線
    signal w_LED_SELECT : std_logic;
begin
    -- 各プロセスが異なる周波数で特定信号をトグル
    -- スイッチがその出力を選んでいなくても常に動作
    p_100_HZ : process (i_clock) is
    begin
        if rising_edge(i_clock) then
            if r_CNT_100HZ = c_CNT_100HZ-1 then -- -1はカウンタが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
                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
                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
                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;

    -- i_enableがHighのときのみo_led_driveを駆動(ANDゲート)
    o_led_drive <= w_LED_SELECT and i_enable;
end rtl;

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;

// 定数(パラメータ)で周波数生成
// 入力クロックは25 kHz(任意に選択)
// 式: (25 kHz / 100 Hz * 50% duty)
// 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;

// カウンタ信号
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;

// 1ビット選択
reg r_LED_SELECT;
wire w_LED_SELECT;

begin
    // 各alwaysブロックが異なる周波数で特定信号をトグル
    // スイッチがその出力を選んでいなくても常に動作
    always @ (posedge i_clock) begin
        if (r_CNT_100HZ == c_CNT_100HZ-1) // -1はカウンタが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)
        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)
        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)
        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

    assign o_led_drive = r_LED_SELECT & i_enable;

    // 代替の多重化器設計(上記と同等):
    // よりコンパクトだが、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

次のステップ:この設計をVHDLまたはVerilogでシミュレーションし、配備前に正しい振る舞いを確認してください。

VHDL

  1. VHDLの条件分岐をマスター:If-Then-Elsif-Else の完全解説
  2. VHDLで乱数生成: 一様分布からOSVVMまで
  3. 上級VHDLクイズ パート2:HDL専門知識をテスト
  4. OSVVMで制約付きランダム検証をマスターする
  5. Modelsim入門:FPGA・ASICシミュレーションのための初心者ガイド
  6. VUnit 101:自動化VHDL検証の実践ガイド
  7. VHDLテストベンチでTEXTIOを使ってBMPビットマップ画像を読み込む
  8. Tclベースのインタラクティブテストベンチでハードウェア検証を強化
  9. プロセス内プロシージャでVHDLステートマシンをクリーンに設計
  10. 上級VHDL習熟度クイズ パート3
  11. VHDLのWait-For文で実行を遅延させる