FPGAのLED制御プログラムを深く理解する:MAX 10 FPGAで学ぶFPGA開発入門(4)(4/5 ページ)
FPGA開発に必要なHDLへの理解を深めるため、MAX 10に用意されているArduino I/Oを利用してのLチカを行い、多灯LEDの制御を含めたプログラミングも解説する。今回も連載で使う「MAX 10 FPGA 評価キット」の読者プレゼントをご用意。
7セグメントLEDの制御
さて、次にここからもう一歩進めて7セグメントLEDのLチカに話を進めてみたい。
7セグメントのLEDも、1桁でやる分にはただのLチカの延長でしかない。面倒なのは1個のLEDなら単にOn/Offで済むのが、7セグメントだと7つ(実際には小数点まで含めると8つ)のLEDのOn/Offを10進数にあわせて切り替える必要があり、何かしらのテーブルを持たないと大変ということだ。加えて言えば配線も若干面倒である(Photo09)。
さて、まずは回路図であるが、図1の様な構造である。今回は手元に2桁の7セグメントLED(Avago Technologiesの「HDSP-K211」)しかなかったので、この下一桁のみを利用している。このHDSP-K211の内部はPhoto10の様になっているが、問題は見てお分かりの通りアノードコモン(プラス極が共有)である。なので、13番ピンにまとめて電源を供給してやる必要がある。
ところがMAX10 Evaluation BoardのArduinoピンには、実は電源が出ていない。先に互換の信号が「一部」出ていると書いたのはこの事で、例えばArduinoならJ2.3にあたるピンには3.3Vが出ているのだが、MAX10 Evaluation Boardにはこれが出ていない。
なので、どこかから3.3Vの出力を取らないといけない。幸いな事にマニュアルによればEP5388QI(オンボードのPMIC)の出力がTP6に出ている。これは本来は消費電力測定用のパッドなのだから、ここから3.3V出力が問題なく取れるので、HDSP-K211の13番ピンをここに接続。後は5〜12番のピンをそのままJ3.3〜J3.8とJ5.1/5.2に割り振った形だ。
ソースはList 4だ。以前との違いは、まず0〜9まで10秒のカウンタとなるので、dec_cntrを4bitに増やした事。それと、新しく7bitのseg_cntrというレジスタを追加したが、これは7セグメントLEDのそれぞれに対応する形だ。具体的な処理はソースを見てもらえれば分かる程度で、dec_cntrの値の0〜9にあわせてseg_cntrの値をbit単位で操作し、その結果をそのままArduino_IOに出力するだけである。
module top( //Clock from oscillator input Clock, //Arduino I/Os inout Arduino_IO6, inout Arduino_IO7, inout Arduino_IO8, inout Arduino_IO9, inout Arduino_IO10, inout Arduino_IO11, inout Arduino_IO12, inout Arduino_IO13 ); reg[25:0] div_cntr; reg[3:0] dec_cntr; reg[6:0] seg_cntr; initial begin div_cntr = 0; dec_cntr = 0; seg_cntr = 0; end always@(posedge Clock) begin div_cntr <= div_cntr + 1; if (div_cntr == 50000000) begin case (dec_cntr) 0 : seg_cntr <= 7'b0000100; // 1111011 1 : seg_cntr <= 7'b1100111; // 0011000 2 : seg_cntr <= 7'b1001000; // 0110111 3 : seg_cntr <= 7'b1000001; // 0111110 4 : seg_cntr <= 7'b0100011; // 1011100 5 : seg_cntr <= 7'b0010001; // 1101110 6 : seg_cntr <= 7'b0010000; // 1101111 7 : seg_cntr <= 7'b1000111; // 0111000 8 : seg_cntr <= 7'b0000000; // 1111111 9 : seg_cntr <= 7'b0000001; // 1111110 default : seg_cntr <= 7'b1111111; // 0000000 endcase dec_cntr <= dec_cntr + 1; if (dec_cntr == 9) begin dec_cntr <= 0; end end end assign Arduino_IO6 = seg_cntr[6] ; assign Arduino_IO7 = seg_cntr[5] ; assign Arduino_IO8 = seg_cntr[4] ; assign Arduino_IO9 = dec_cntr[0] ; assign Arduino_IO10 = seg_cntr[3] ; assign Arduino_IO11 = seg_cntr[2] ; assign Arduino_IO12 = seg_cntr[1] ; assign Arduino_IO13 = seg_cntr[0] ; endmodule
注意点はアノードコモン方式であること。5〜12番ピンをHiにすると消灯、Loにすると点灯という負論理になっているので、これにあわせてseg_cntrに設定するあたりは本来の逆となっている。また小数点(HDSP-K211の9番ピン)は1秒おきに点滅ということにしたので、dec_cntrのLSBの値をそのままassignしている。これを動かすと、Movie02の様にちゃんと動作するはずだ。
ということで7セグメントLEDの1桁駆動は比較的簡単だったが、この桁数を増やそうとするとやや面倒である。桁数を増やすためにはダイナミック駆動をするのが一般的だが、アノードコモンでこれをやるにはちょっと回路に細工が必要である。
もう1つの問題が処理の遅延である。Photo11はこの7セグメントLEDのTechnology Mapだが、Photo06と比べてもさらに回路が延びており、どうみても1サイクルで処理が終わるようには思えない。実はこれ、全ての回路をシーケンシャルで動かしているのが問題で、この結果として、1秒毎に表示処理を行っている時は、何サイクルかクロックの割り込みを取り逃している。
冒頭で「本来の周期よりも若干長い」と書いたのはこれが理由である。解決は簡単で、クロック信号を数えて1秒を割り出す部分と、そのあとの表示処理を分離すれば良い。次回はこのあたりを説明したい。
Copyright © ITmedia, Inc. All Rights Reserved.