第6回: 実習(3): FPGAへの論理回路の実装(分周回路)
今回は、カウンタの応用として、周波数を変えたクロック信号をつくる
分周回路をつくって、好きなな速さでカウントが進む回路をつくってみましょう。
8ビットカウンタ
まず練習として、8ビットカウンタをつくってみます。
プロジェクトの作成
前回の実習(2)と同様に、
Xilinx ISE Project Navigatorを使ってVHDL記述の論理回路の
設計と論理合成(コンパイル)を行います。
基本的な操作は、実習(1)や実習(2)の
手引き書を参考にしてください。
以下では、異なる点のみを記載しておきます。
- File→New Projectで、新しいプロジェクトの作成を開始します。
プロジェクト名は"count8div"としておきましょう。
- "Create a new source"(新規にファイルを作る)の画面では、何も入力せずに次へ。
- "Add extisting sources"では、以下の4つのファイル(ダウンロードしてデスクトップ等に保存しておく)を、「Add Source」ボタンで指定して追加する。追加後、それらのファイルの中身を確認されるのでOKを押しておく。
今回作る回路の全成は3つのコンポーネント(部品)からなり、
3つのVHDLファイルはそれぞれの回路が記述されています。
それぞれのコンポーネントの役割は以下の通りです。
- count8div_top : 全体のとりまとめ。実際のスイッチ・LEDがつながっている。
スイッチ・LEDともに「負論理」なので、わかりやすいようにnotを
とった信号(rst, q)を内部で使うようにしている点に注意。
- count8 : 8ビットカウンタの本体。これは前回のファイルと同じ。
- div : 実習で使っているFPGAボード(EDX001)には、1kHzのクロック信号が
ありますので、これを使います。
ただしこの1kHzのクロック信号を直接カウンタに与えると、変化が速すぎて
目でみてわからない(1/1000秒ごとにカウントアップ)ので、
もっと周波数の低いクロック信号をつくってみます。
まずは1秒に1ずつカウントアップするように、
1Hzのクロック信号をつくってみます。
このように低い周波数のクロック信号を作る回路を分周回路と呼びますが、
これの実体は、実はカウンタそのものです。
div.vhdの中身をみてよく理解しましょう。
与えるクロック信号clk_i (1kHz)ごとに分周用のカウンタをカウントアップし、
999の次には0に戻るようにしています。
そしてこのときだけ出力(clk_o)を1にしています。
結果としてclk_oは、clk_iの1000回に1回だけ1、他は0となるため、
周期が1000倍(=周波数が1/1000)の1Hzのクロック信号となります。
これを生成したクロックは、全体構成count8div_topでは"clk_cnt"という名前の
信号にしています。
- あとは全体構成のcount8_topを選んだ状態でコンパイルをかけて、
作成されたcount8div_top.bitをEDX001に転送すれば、
LEDの表示(カウンタの値の2進数表記)gあ1秒に1ずつ増えていくはずです。
またSW(D)を押すとリセットがかかります。
全体構成を自分で描いてみてよく理解した上で、実際に動作をさせてみましょう。
またdiv.vhdを変更し、別の速さ(例えば10Hzや0.5Hz)でカウント動作をさせてみましょう。
ただしそのとき、分周用のカウンタのビット数と取り得る値の範囲には気をつける必要があります。
div.vhdでは分周用カウンタcntは11ビットとして宣言しています。
11ビットの2進数で扱える値は211=2048までです。
div.vhdではcntで取り得る値は最大で999ですので、11ビットで扱える範囲に
おさまっていますが、もっと分周比を大きくしたい(生成するクロック信号の
周波数を低くしたい)ときには、宣言するcntのビット数をそれにあわせて
増やす必要があります。
ちなみにこの例ではcntのビット数は10ビットでも足りますが、
余裕を見て(?)11ビットで宣言しています。
ハードウエアリソースの制限がぎりぎりの場合は、10ビットとするべきでしょう。
このように分周回路の速度(分周比)を容易に変えられるのも、
HDLでの論理回路設計のメリットと言えます。
7セグメントLEDでの表示(オプション)
時間に余裕のある人は、カウンタの値を7セグメントLEDに表示する機能を
追加してみましょう。
以下のファイルを使って新規にプロジェクトを作成(またはさきほどのcount8divを修正)してみてください。
なお4桁の7セグメントLEDの駆動は、一筋縄ではいかず、ダイナミック駆動と呼ばれるテクニックが必要です。
今回は詳細は理解しなくてもよいですが、興味のある人はこちらなどの情報とseg7.vhdの記述を見比べてみてください。
全体構成のcount8div7seg_top.vhdの、さきほどのcountdiv_top.vhdからの変更点は以下の3つです。
- エンティティ記述:以下のように7セグメントLED関係の信号SA, SGを追加
Port ( PSW : in STD_LOGIC_VECTOR (3 downto 0);
LED : out STD_LOGIC_VECTOR (7 downto 0);
CLK : in STD_LOGIC;
SA : out STD_LOGIC_VECTOR(3 downto 0);
SG : out STD_LOGIC_VECTOR(7 downto 0));
- コンポーネント宣言: 7セグメントLED駆動回路seg7の宣言を追加。d0~d3が、それぞれ1の位(右端)~1000の位(左端)に表示するべき値(4ビット2進数)。ちなみに0~9はその数字が、10~15(16進数でA~F)は、アルファベットA~Fが表示される。
component seg7 is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
d0 : in STD_LOGIC_VECTOR (3 downto 0);
d1 : in STD_LOGIC_VECTOR (3 downto 0);
d2 : in STD_LOGIC_VECTOR (3 downto 0);
d3 : in STD_LOGIC_VECTOR (3 downto 0);
sa : out STD_LOGIC_VECTOR (3 downto 0);
sg : out STD_LOGIC_VECTOR (7 downto 0));
end component;
- インスタンス呼び出し: 7セグメント駆動回路を呼び出し。1の位にはカウンタの出力qの下位4ビット、10の位にはqの上位4ビット、100の位と1000の位には"0"を節即している。
iseg7: seg7 port map(CLK, rst, q(3 downto 0), q(7 downto 4), "0000", "0000", SA, SG);
なおカウンタの表示は「16進数表記」ですので、そのつもりで動作を確認してみてください。
戻る