第12回: 実習(3): FPGAへの論理回路の実装(3)
今回の演習は、最後のまとめとして、
10進4桁のカウンタの出力を、4桁の7セグメントLEDに表示させてみましょう。
ダイナミック表示と駆動回路
7セグメントLEDは、数字を構成する「8」の字の7個のLEDと
右下の小数点用のLEDから成っています。
各LED(セグメント)には、↑のようにSG0からSG7の番号がついていて、
それぞれの名前の出力としてFPGAにつながっています。
ただし負論理なので、例えば出力SG0='0'とすると、
一番上のLED(セグメント)が点灯することになります。
例えば「1」の字を表示するためには、SG1とSG2のみ'0'、
他を'1'とすればよいことになります。
この調子で、表示したい値(2進数4桁で"0000"(0)〜"1001"(9))に
応じて、SG0〜SG7の値を設定すれば、好きな数字を表示できることになります。
この調子で4桁もいけばよいように思えますが、残念ながら
そう簡単にはいきません。
というのも、4個の7セグメントLEDは、SG0〜SG7が
共通につながっています。
つまりSG0='0'とすると、4桁のすべての7セグメントLEDの
上のLED(セグメント)が点灯してしまうことになります。
これでは、好きな4桁の数値を表示できないわけですが、
その代わり、各桁を点灯させるか消灯させるかを決める
SA0〜SA3という信号があり、これもFPGAにつながっています。
これは、(負論理なので)'0'になった桁の7セグメントLEDのみ、
SG0〜SG7に対応して各LED(セグメント)が点灯する、という
機能をもっています。
これをうまく使うと、次の4つの状態を順に変えていけば、
1桁ずつ数値を表示できることになります。
- SA0のみ'0'、他を'1'とし、一番右の桁に表示させたい数字に対応するSG0〜SG7を与える
- SA1のみ'0'、他を'1'とし、右から2番目の桁に表示させたい数字に対応するSG0〜SG7を与える
- SA2のみ'0'、他を'1'とし、右から3番目の桁に表示させたい数字に対応するSG0〜SG7を与える
- SA3のみ'0'、他を'1'とし、一番左の桁に表示させたい数字に対応するSG0〜SG7を与える
もちろん、この1.〜4.は、それぞれ1桁ずつしか表示されていませんが、
これを「高速」(例えば毎秒100回程度)に切り替えれば、
残像現象によって、人間の目には、すべてが同時に点灯しているように見えます。
このように、1桁ずつの表示を高速に切り替える方法を
ダイナミック点灯(駆動) と呼びます。
4桁10進カウンタ(7セグメントLED表示つき)
このダイナミック駆動を行う回路を用いて、4桁の10進数の数字を表示させる
回路を設計してみましょう。
表示させる値は、例として10進数4桁のカウンタの値とし、
1秒(あるいは0.1秒)ごとにカウンタの値を増やし、
ストップウオッチ的な動作にしてみます。
全体構成
全体の構成を↑この図のようにしてみます。
以下に、各要素の入出力と、機能をまとめてきます。
counter1
counter1は、1桁分の10進カウンタとします。
カウントの基準となるクロックCLK、(非同期)リセットRST、
1桁分(4ビット)の出力Q、出力が9→0になるときに
'0'→'1'となる桁上げ出力COをもちます。
entity counter1 is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
Q : out STD_LOGIC_VECTOR (3 downto 0);
CO : out STD_LOGIC);
end counter1;
参考:設計例
counter4
counter4は、counter1を4桁分まとめた、10進4桁のカウンタとします。
1の桁のcounter1の桁上げ出力COを、次の10の桁のcounter1のクロックCLKに
与えることで、09→10→11→・・・というカウント動作を実現できます。
全体のカウントの基準となるクロックCLK、非同期リセットRST、
1の桁〜1000の桁の出力Q0〜Q3(それぞれ4ビット)、
全体の桁上げ出力COをもちます。
entity counter4 is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
Q0 : out STD_LOGIC_VECTOR (3 downto 0);
Q1 : out STD_LOGIC_VECTOR (3 downto 0);
Q2 : out STD_LOGIC_VECTOR (3 downto 0);
Q3 : out STD_LOGIC_VECTOR (3 downto 0);
CO : out STD_LOGIC);
end counter4;
参考:設計例
dec7seg
dec7segは、与えられた4ビットの数値を数字として表示する用に、
対応する7セグメントLEDのLED(セグメント)につながるSG0〜SG7を
決定する回路です。
表示するべき数値を与えられる入力D(4ビット)と、
7セグメントLEDにつながる出力SG0〜SG7をもちます。
entity dec7seg is
Port ( D : in STD_LOGIC_VECTOR (3 downto 0);
SG : out STD_LOGIC_VECTOR (7 downto 0));
end dec7seg;
sel4
sel4は、ダイナミック駆動を制御する、この回路の中心的な回路です。
各桁の表示の切り替えクロックCLK、非同期リセットRSTをもち、
各桁に表示するべき4ビットの値Q0〜Q3のうちの1つを選んで出力Qへわたし、
それにあわせて、表示するべき桁のSA0〜SA3のいずれか1つのみ'0'とします。
例えば、まず最初はQ=Q0かつSA0='0'とし、
その次のタイミングではQ=Q1かつSA1='0'とすればよいことになります。
entity sel4 is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
Q0 : in STD_LOGIC_VECTOR (3 downto 0);
Q1 : in STD_LOGIC_VECTOR (3 downto 0);
Q2 : in STD_LOGIC_VECTOR (3 downto 0);
Q3 : in STD_LOGIC_VECTOR (3 downto 0);
Q : out STD_LOGIC_VECTOR (3 downto 0);
SA : out STD_LOGIC_VECTOR (3 downto 0));
end sel4;
※ヒント:これは、1の桁〜1000の桁を表示している状態4つの状態
SA0_ST〜SA3_STをもつステートマシンとして設計できそうです。
div1s
div1sは、1kHzの基準クロックCLKをもとに、カウンタを動かす
1Hzのクロックを作る分周回路です。
entity div1s is
Port ( CLK : in STD_LOGIC;
CLK1S : out STD_LOGIC;
RST : in STD_LOGIC);
end div1s;
div3ms
div3msは、1kHzの基準クロックCLKをもとに、ダイナミック駆動の制御回路
sel4を動かすクロックを作る分周回路です。
ダイナミック駆動の制御クロックは、適当な値でよいのですが、
例として3msごと(333Hz)としてみましょう。
entity div3ms is
Port ( CLK : in STD_LOGIC;
CLK3MS : out STD_LOGIC;
RST : in STD_LOGIC);
end div3ms;
※3msごとに桁が切り替わり、4桁でひとまわりですから、
表示の点滅の周期は3ms×4=12ms、つまり約80Hzということになります。
top_counter4
以上の要素回路を、まとめている全体の回路です。
各要素回路をcomponent宣言し、インスタンス呼び出しして接続するだけでよいでしょう。
entity top_counter4 is
Port ( CLK : in STD_LOGIC;
RST : in STD_LOGIC;
SG : out STD_LOGIC_VECTOR (7 downto 0);
SA : out STD_LOGIC_VECTOR (3 downto 0);
LED0 : out STD_LOGIC);
end top_counter4;
ピン定義ファイル
top_counter4をつかって論理合成する際に、
EDX-001用のピン定義ファイル(top_counter4.ucf)が必要ですが、それには↓の内容を
使ってください。
LED0には、counter4の桁上げ出力COをつないでおきましょう。
NET "CLK" LOC = "P18";
NET "RST" LOC = "P50";
NET "LED0" LOC = "P65";
NET "SG<7>" LOC = "P29";
NET "SG<6>" LOC = "P30";
NET "SG<5>" LOC = "P31";
NET "SG<4>" LOC = "P40";
NET "SG<3>" LOC = "P41";
NET "SG<2>" LOC = "P42";
NET "SG<1>" LOC = "P43";
NET "SG<0>" LOC = "P44";
NET "SA<3>" LOC = "P46";
NET "SA<2>" LOC = "P47";
NET "SA<1>" LOC = "P48";
NET "SA<0>" LOC = "P49";
レポート
上記の4桁10進カウンタ、あるいはそれに独自の機能を加えたり改造した回路を
設計し、シミュレーションやEDX-001での動作を行う。
- レポート内容:設計した回路の仕様、VHDLソース、シミュレーション結果、動作結果など
- 提出:この科目の期末試験の開始時点(それ以前の提出は飯田先生か田中先生へ) ※電子メールでの提出もOK。24時間以内に受理の返信がない場合は、添付ファイルが大きすぎる等で届いていない可能性が高いので、zip形式に圧縮するなどして再送&別便で確認メールを送ること)
- 注意:内容に関して、文献、Webページを参考にしたり、友人と相談することは大いにやってください。ただし、それらは「出典」として明記すること。
- その他、不明な点、質問などは秋田(akita@merl.jp)まで。
レポートの採点基準
- 基本点:C=4桁10進カウンタの完成、B〜A=独自機能拡張・改造の程度に応じて
- オプション点:シミュレーション結果、実機での動作結果=それぞれ「+」、
レポートの構成(章立て)がしっかりしている=「○」
- 点数への換算:こちらを参照のこと
補足
他のスイッチやLEDなどを使う際には、以下から使うスイッチ・LEDの分のみを
作った回路の*.ucfにコピーして使ってください。
(vector形式の信号名を使う場合は、適宜NETの名称を修正すること。
例:LED0→LED<0>)
ちなみにBUZはブザーで、4kHz程度のクロックを与えると音が鳴ります。
またCLK0は18.432MHz、CLK1は72kHzのクロック信号です。
NET "LED0" LOC = "P65";
NET "LED1" LOC = "P64";
NET "LED2" LOC = "P63";
NET "LED3" LOC = "P62";
NET "LED4" LOC = "P60";
NET "LED5" LOC = "P59";
NET "LED6" LOC = "P58";
NET "LED7" LOC = "P57";
NET "SWA" LOC = "P50";
NET "SWB" LOC = "P51";
NET "SWC" LOC = "P54";
NET "SWD" LOC = "P56";
NET "BUZ" LOC = "P96";
NET "CLK0" LOC = "P88";
NET "CLK1" LOC = "P91";
戻る