FPGAでLチカ!クロック同期カウンタを使ったLED点滅回路をVHDLで記述する【超初心者のFPGA開発2】

こんにちは。
新人の”モーションT.K”です。
前回の記事では、スイッチを押すとLEDが点灯するデジタル回路(論理回路)をVHDLで記述し、FPGAに実装しました。

さて、今回はクロック同期カウンタを使ったLED点滅回路を設計します!
と、その前に前回の内容をサラッとおさらいしておきましょう。

前回の実験のおさらい(VHDL記述の部分)

前回のVHDLコードはとてもシンプルで、回路の内容を示す部分は以下の図のようにLED <= SW;一行だけでした。とてもとてもシンプルです。配線しただけです。

スイッチ押下でLED点灯VHDL
図:スイッチ押下でLED点灯する回路のVHDL記述

ここで、LED <= SW; が意味する回路は”組み合わせ回路“と呼ばれていて、論理回路の基本となる回路です。

組み合わせ回路とは?

組み合わせ回路とは、以下の図のように入力の値が定まれば、出力の値が確定する回路のことです。

組み合わせ回路イメージ
図:組み合わせ回路イメージ

VHDLでは組み合わせ回路を記述するために、同時処理文というものが用意されています。

LED <= SW;のような文は”同時処理代入文”と呼ばれており、not and, orなどの論理演算子を書き加えることもできます。他には、when else を用いる”条件付き信号代入文”や with select when を用いる”選択信号代入文”などがあります。
組み合わせ回路を記述する同時処理文は、書かれた順番に関係なく、並行処理されることになっています。(ここが C やPython などのプログラミング言語と違うところです。)

さて、今回の実験ではもう少し複雑な回路を設計してLチカしてみます。
具体的には、FPGAへ外部のクロックを入力して、数を数えて、1秒周期でLEDをチカチカさせる回路です。そのためには、組み合わせ回路に加えて順序回路というものが必要です。

順序回路とは?

順序回路とは、以下の図のようにメモリのように内部状態を記憶する回路があって、入力とその記憶回路の状態によって出力が決まる回路のことです。例えば、前回の値を記憶していて、その値に1を足した値を記憶して、その値にまた1を足した値を記憶して、、、といった処理を繰り返す回路(カウンタ回路)は順序回路の一つです。

順序回路イメージ
図:順序回路イメージ

また、VHDLで順序回路を記述するには、順次処理文を使用します。順序回路の内部には、組み合わせ回路が組み込まれているので同時処理文も使用します。順序処理文の使い方は実際に回路を設計しながら見ていきたいと思います。

クロック同期カウンタでLEDを点滅させる!

それでは、実際に回路を記述していきます。

回路の仕様

クロック同期LED点滅FPGA回路の仕様
  • 1秒間隔でLEDが点滅
  • 入力ポートは50MHzの外部クロックに、出力ポートはLEDと接続
  • クロック同期カウンタによって500msを計測。
  • 500ms毎にトグル信号を発生
  • トグル信号をLEDへ出力

以上の仕様から以下のブロック図を作成しました。

1s周期点滅回路イメージ
図:1秒周期LED点滅回路

VHDL記述

上の図を参考に記述したVHDLコードの全体像は以下の図の通りです。

1s周期lLED点滅回路VHDLソース
図:1秒間隔LED点滅回路のVHDLコード

詳しく見ていきます。

エンティティ部

図:entity部で回路名と使用ポートの宣言

回路名(デザイン名)は、T500MS_2(修正版なので_2がついています。)としました。入力ポートして単線のCLOCKを、出力ポートとして単線のLEDを宣言しています。

アーキテクチャ部

図:回路中継用の配線VHDL記述

続いてアーキテクチャ部の先頭で、回路内部で使用する信号(中継用の配線)を宣言します。2500万回つまり500ms数えるカウンタ用の信号線をCNT(範囲は整数0~24999999)、初期値が’0’で500ms毎に値が反転するトグル動作用の信号をDPとして宣言しました。

クロック同期500msタイマ

図:500msタイマ回路のVHDL記述

アーキテクチャ部内で順序回路を記述します。まずは500msタイマ部分を見ていきます。process文を用いることで順序回路が記述できます。processの後のかっこ内には、順序回路が動作するきっかけとなる信号名を記述します。今回はCLOCK信号のみによって回路を動作させるので、CLOCKだけを記述しています。
このCLOCKによって動作させる順序回路を同期回路と呼びますが、後ほど紹介します。

その後に続くif文で回路の内容を記述しています。CLOCKの立ち上がりエッジを検出するたびにCNTが24999999であるかを比較しており、一致している場合はCNTをゼロクリアさせます。CNTが24999999以外の場合は、CNTに1を足します。

以上の記述で、500msに1回なにかしらの処理をするようなタイマを記述できます。

同期回路とは?非同期回路との違いは?

さて、さきほど出てきた同期回路とは何なのでしょうか?
同期回路とは、同一のクロック信号(一定の周期で’1’と’0’を出力する信号)の立ち上がりエッジ(信号が’0’から’1’に変化)、もしくは立ち下がりエッジ(信号が’1’から’0’に変化)に同期して動作する回路群のことです。
一方で、入力されるクロック信号やチェックするエッジの方向が異なる回路群は非同期回路と呼ばれます。

同期回路の利点は、同一のクロックによって回路が動作するため回路同士のタイミングが取りやすく高速動作することです。このことは信頼性の高い回路(ちゃんと目論見通りに動作する回路)を設計する上で重要です。

図:同期回路と非同期回路の違い

トグル動作回路

本題に戻って、トグル動作部分の記述を見ていきます。

図:トグル動作

トグル動作もCLOCKに同期させています。CLOCKの立ち上がり時にCNTが24999999と等しければ、論理演算子のnot を使用してDPを反転させます。こうすることで、500ms毎に’1’と’0’に変化するトグル動作部分を記述できます。

そして最後に、Process文の外側でDPをLEDに配線し、VHDLコードは完成です。

テストベンチ&シミュレーション

続いて記述した回路の動作を確かめるために、テストベンチを作成してシミュレーションを行います。
以下のようなテストベンチを作成しました。

図:1s周期LED点滅回路のテストベンチ

シミュレーションの結果は以下のようになり、期待した動作をしています。

ピンアサイン&コンパイル&実装

シミュレーションがうまくいったので、FPGAにピンをアサインします。EDA301の回路図やマニュアルを見るとクロックはFPGAのB9ピン、LEDはC11ピンに配線されていたので、以下の図のようにピンをアサインしました。

そしてコンパイルし、FPGAに実装します。

クロック同期で500ms間隔LED点滅回路が動いた!

動きました!やりました!
今回は順序回路や同期回路を学んで実装したので、ちゃんと設計した感覚があります!

次回の実験では、スイッチ押下するとLED点滅周期が変化するFPGAを開発したいと思います。
ありがとうございました。

参考文献
・はじめてのVHDL(書籍)
・ビジュアル論理回路入門(書籍)
[RTL 設計ビギナー必見] 同期設計と非同期設計の違い – 半導体事業 – マクニカ (macnica.co.jp)
Beryll の FPGA でクロック同期によるLチカ![#1/3] – 半導体事業 – マクニカ (macnica.co.jp)