FPGAのLED制御プログラムを深く理解するMAX 10 FPGAで学ぶFPGA開発入門(4)(4/5 ページ)

» 2015年11月13日 07時00分 公開
[大原 雄介MONOist]

7セグメントLEDの制御

 さて、次にここからもう一歩進めて7セグメントLEDのLチカに話を進めてみたい。

 7セグメントのLEDも、1桁でやる分にはただのLチカの延長でしかない。面倒なのは1個のLEDなら単にOn/Offで済むのが、7セグメントだと7つ(実際には小数点まで含めると8つ)のLEDのOn/Offを10進数にあわせて切り替える必要があり、何かしらのテーブルを持たないと大変ということだ。加えて言えば配線も若干面倒である(Photo09)。

7セグメントLEDでのLチカ実装例 Photo09:ブレッドボードを利用して実装。黒い配線が3.3Vラインへのもの

 さて、まずは回路図であるが、図1の様な構造である。今回は手元に2桁の7セグメントLED(Avago Technologiesの「HDSP-K211」)しかなかったので、この下一桁のみを利用している。このHDSP-K211の内部はPhoto10の様になっているが、問題は見てお分かりの通りアノードコモン(プラス極が共有)である。なので、13番ピンにまとめて電源を供給してやる必要がある。

MAX 10と7セグメントLED「HDSP-K211」の配線図 図1 回路図

 ところが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
List4

 注意点はアノードコモン方式であること。5〜12番ピンをHiにすると消灯、Loにすると点灯という負論理になっているので、これにあわせてseg_cntrに設定するあたりは本来の逆となっている。また小数点(HDSP-K211の9番ピン)は1秒おきに点滅ということにしたので、dec_cntrのLSBの値をそのままassignしている。これを動かすと、Movie02の様にちゃんと動作するはずだ。

Movie02

 ということで7セグメントLEDの1桁駆動は比較的簡単だったが、この桁数を増やそうとするとやや面倒である。桁数を増やすためにはダイナミック駆動をするのが一般的だが、アノードコモンでこれをやるにはちょっと回路に細工が必要である。

 もう1つの問題が処理の遅延である。Photo11はこの7セグメントLEDのTechnology Mapだが、Photo06と比べてもさらに回路が延びており、どうみても1サイクルで処理が終わるようには思えない。実はこれ、全ての回路をシーケンシャルで動かしているのが問題で、この結果として、1秒毎に表示処理を行っている時は、何サイクルかクロックの割り込みを取り逃している。

「Technology Map Viewer」での表示。右端が急に複雑化している Photo11:「Technology Map Viewer」での表示。右端が急に複雑化しているのが分かる

 冒頭で「本来の周期よりも若干長い」と書いたのはこれが理由である。解決は簡単で、クロック信号を数えて1秒を割り出す部分と、そのあとの表示処理を分離すれば良い。次回はこのあたりを説明したい。

Copyright © ITmedia, Inc. All Rights Reserved.