← 講義ポータルへ戻る 第5回講義:実装(最初の山場)

第4章:最初のLチカ ― 自分のVerilogで光らせる

いよいよ、自分で書いた回路を Basys 3 で動かします。最初の題材は、誰もが通る「Lチカ」(LEDをチカチカ点滅させる)です。テンプレートも、特別な“殻”も要りません。クロック・リセット・LEDだけの、ごく短いVerilogを自分で書いて、それを実機で光らせます。これがFPGAそのものの第一歩です。

この章で書くファイルは、たった1つ(数十行のVerilog)です。 むずかしいことはしません。「カウンタを回して、その一番上のビットでLEDを光らせる」だけ。第1章で分解したLUTやフリップフロップが、ここで実際に動き出します。

4.1 何を作るか ― カウンタでLEDを点滅させる

LEDを点滅させる一番素直な方法は、カウンタです。クロック(Basys 3 では100MHz=1秒間に1億回)が来るたびに1ずつ増える数を用意し、その一番上のビットをLEDにつなぎます。カウンタが増えていくと、上位ビットはゆっくり 0→1→0→1… と切り替わるので、LEDがゆっくり点滅して見える、という仕組みです。

   100MHzのクロックで増え続けるカウンタ
   counter: 0,1,2,3, ... どんどん増える(2進数で桁上がりしていく)
            ┌─ 下位ビット:すごく速く 0↔1(速すぎて目では見えない)
            └─ 上位ビット:ゆっくり 0↔1 ← これをLEDにつなぐと点滅が見える
   ───────────────────────────────────────────────────────────
   counter[25] は 2^25回ごとに反転 → 点滅周期は約0.67秒(ちょうど見やすい)

4.2 Lチカのコードを書く(blink.v)

作業用フォルダに blink.v という名前で、次のファイルを作成します。これが本講座で最初に自分で書くRTLです。

目的: 100MHzで動くカウンタを作り、その上位ビットで Basys 3 のLEDを点滅させる。

`default_nettype none

module blink (
    input  wire clk,    // 100MHzクロック(Basys 3 のピンW5)
    input  wire rst,    // リセット(中央ボタン btnC:押すと点滅が止まり消灯)
    output wire led     // LED0(点滅出力)
);

    // 26ビットのカウンタ。クロックごとに1ずつ増える。
    reg [25:0] counter;

    always @(posedge clk) begin
        if (rst)
            counter <= 26'd0;            // リセット中は0に保つ
        else
            counter <= counter + 1'b1;   // クロックごとに+1
    end

    // 一番上のビット(counter[25])をLEDへ。約0.67秒ごとに点いて消える。
    assign led = counter[25];

endmodule

4.2.1 コードを1行ずつ読む

① 入出力の宣言

module blink (clk, rst, led)。このLチカが外の世界とやり取りする足は3本だけ。クロック入力・リセット入力・LED出力です。シンプルそのもの。

② カウンタの用意

reg [25:0] counter; = 26ビットの記憶素子。第1章で学んだとおり、regalways @(posedge clk)フリップフロップ(記憶素子)になります。ここでは26個ぶんです。

③ クロックごとに+1

always @(posedge clk) は「クロックの立ち上がりのたびに」の意味。中で counter <= counter + 1'b1; として、毎クロック1ずつ増やします。100MHzなら1秒に1億回です。

④ リセット

if (rst) counter <= 0;。ボタン(btnC)を押している間はカウンタを0に保ち、点滅を止めます(消灯)。離すとまた増え始めます。

⑤ LEDへの接続

assign led = counter[25];。カウンタの最上位ビットをLEDへ。これが約0.67秒ごとに 0↔1 するので、LEDがゆっくり点滅します。

⑥ なぜ counter[25]?

100MHzでは counter[25] の1周期(点いて消えるまで)が約0.67秒。ビット番号を変えれば点滅速度が変わります(4.5で実験)。ここが自分で設計する面白さです。

4.3 ピンの対応表(.xdc)を書く

blink の3本の足(clkrstled)が、Basys 3 のどの物理ピンにつながるかをVivadoに教えます。作業フォルダに blink.xdc を作成します。ピン番号はDigilent公式のマスターXDCに基づきます。

## Basys 3 ピン制約(本章で使う3本だけ)

## 設定電圧(DRC警告を避ける定番のおまじない)
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]

## 100MHzクロック(ピンW5)
set_property -dict { PACKAGE_PIN W5  IOSTANDARD LVCMOS33 } [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]

## 中央ボタン btnC(ピンU18)→ リセット
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports rst]

## LED0(ピンU16)→ 点滅出力
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports led]

4.4 Vivadoで合成・書き込みする

第3章で導入したVivadoに、書いた2ファイル(blink.vblink.xdc)を読み込ませ、Basys 3 へ書き込みます。各ステップに「実行するとこうなる」を添えます。

  1. 新規プロジェクト作成: 「Create Project」でRTLプロジェクトを新規作成。対象デバイスで XC7A35T(パッケージ cpg236、スピードグレード -1を選びます(Basys 3 のボードファイルがあればボード一覧から選んでも可)。
  2. 設計ファイルを追加: 「Add Sources」で blink.v を design source として追加します。
  3. 制約ファイルを追加: 「Add Sources」→「Add or create constraints」で blink.xdc を追加します。
  4. 合成(Run Synthesis): RTLがLUT・フリップフロップへ割り当てられます。
    こうなる: 完了で緑のチェック。利用率はごくわずか(FFを26個ほど使う程度)です。
  5. インプリメンテーション(Run Implementation): 使う部品がArtix-7の実際の場所へ配置・配線されます。
  6. ビットストリーム生成(Generate Bitstream): Basys 3 へ書き込む設定データ(.bit)ができます。
  7. 書き込み: Basys 3 をUSB接続し電源ON。「Open Hardware Manager」→「Open Target」→「Auto Connect」→「Program Device」。
    こうなる: 書き込んだ瞬間、回路が動き出します。

つまずきどころ(ボードが見つからない): 「Auto Connect」でボードが出ない場合は、第3章3.5のケーブルドライバ・USBポート・充電専用ケーブルの確認に戻ってください。FPGAで最も多いつまずきがここです。

4.5 光った! ― そして点滅速度を「自分で」変えてみる

書き込みが成功すると、LED0 が約0.67秒ごとにゆっくり点滅します。中央ボタン(btnC)を押すと点滅が止まって消灯し、離すとまた点滅が始まります。自分で書いたVerilogが、本物のFPGAの上で動いている――これが第一歩です。

ここからが、FPGAの楽しいところです。blink.v の最後の行 assign led = counter[25];ビット番号を変えるだけで、点滅速度が変わります。書き換えたら、もう一度合成して書き込むだけ。何度でも試せます。

   LEDにつなぐビットを変えると、点滅速度が変わる(100MHzの場合)
 ───────────────────────────────────────────────────────────
   assign led = counter[23];  →  1周期 約0.17秒(速い:チカチカ)
   assign led = counter[25];  →  1周期 約0.67秒(ちょうど見やすい)★今回
   assign led = counter[27];  →  1周期 約2.7秒 (ゆっくり:ぴこー…ぴこー)
        ※ビット番号を1つ上げるごとに、点滅周期は約2倍になる

これがFPGAの醍醐味: 「直して → すぐ試す」を、お金も製造待ちもなしに、何度でも回せます。counter[27] を使うなら、カウンタの幅も reg [27:0] counter; に広げるのを忘れずに(ビット28個ぶん必要なので)。こうした小さな実験を重ねるうちに、「自分で設計している」という手応えが育っていきます。

💡 コラム:なぜ「カウンタの上位ビット」で点滅するのか

2進数のカウンタは、1ずつ増えるたびに各ビットが規則的に反転します。一番下のビット(counter[0])は毎クロック反転、その上は2クロックごと、さらに上は4クロックごと……と、上のビットほど反転がゆっくりになります。一般に counter[n]2のn乗クロックごとに反転します。

Basys 3 の100MHzでは、1クロックは10ナノ秒。counter[25] が反転するのは 225クロック = 約0.34秒ごと。点いて消えるまでの1周期はその2倍で約0.67秒、という計算です。「速すぎて見えない高速クロックを、カウンタで“間引いて”目に見える速さにしている”――これがLチカの種明かしです。この考え方は、後の章で「ゆっくりした動き」を作るときにも何度も使います。

4.6 この章のまとめ

これでFPGAの基本の流れ(書く → ピンを割り当てる → 合成して書き込む → 動く)が一巡しました。次の第5章では、この流れを土台に、スイッチ入力・複数のLED・7セグメント表示を使って、もっといろいろ「作って遊ぶ」段階に進みます。