第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章で学んだとおり、reg + always @(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本の足(clk・rst・led)が、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]
PACKAGE_PIN W5: 信号をチップの物理ピンW5へつなぐ指定。W5はBasys 3 の100MHz発振器のピンです(第2章参照)。IOSTANDARD LVCMOS33: Basys 3 のこれらのピンは3.3Vでやり取りするため、この規格を指定します。create_clock ... -period 10.00: 「clkは周期10ns(=100MHz)」とVivadoに教え、タイミング検証を正しく行わせます。- 信号名は
blinkのポート名と一致:[get_ports clk]などの名前は、Verilogの足(clk・rst・led)とぴったり同じにします。ずれるとエラーになります。
4.4 Vivadoで合成・書き込みする
第3章で導入したVivadoに、書いた2ファイル(blink.v と blink.xdc)を読み込ませ、Basys 3 へ書き込みます。各ステップに「実行するとこうなる」を添えます。
- 新規プロジェクト作成: 「Create Project」でRTLプロジェクトを新規作成。対象デバイスで XC7A35T(パッケージ
cpg236、スピードグレード-1)を選びます(Basys 3 のボードファイルがあればボード一覧から選んでも可)。 - 設計ファイルを追加: 「Add Sources」で
blink.vを design source として追加します。 - 制約ファイルを追加: 「Add Sources」→「Add or create constraints」で
blink.xdcを追加します。 - 合成(Run Synthesis): RTLがLUT・フリップフロップへ割り当てられます。
こうなる: 完了で緑のチェック。利用率はごくわずか(FFを26個ほど使う程度)です。 - インプリメンテーション(Run Implementation): 使う部品がArtix-7の実際の場所へ配置・配線されます。
- ビットストリーム生成(Generate Bitstream): Basys 3 へ書き込む設定データ(
.bit)ができます。 - 書き込み: 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 この章のまとめ
- 自分でRTLを書いた: テンプレートも殻も使わず、
blink.v(カウンタ+LED出力)を自分の手で書いた。 - ピンを割り当てた:
.xdcでclk=W5・rst=U18・led=U16 を指定した。 - 実機で光らせた: Vivadoで合成・配置配線・書き込みを通し、LEDを点滅させた。
- 自分で改造して試した: ビット番号を変えて点滅速度を変え、「直してすぐ試す」を体験した。
これでFPGAの基本の流れ(書く → ピンを割り当てる → 合成して書き込む → 動く)が一巡しました。次の第5章では、この流れを土台に、スイッチ入力・複数のLED・7セグメント表示を使って、もっといろいろ「作って遊ぶ」段階に進みます。