デジタル回路のスイッチ入力の同期化_1msecパルス生成

デジタル回路のスイッチ入力の同期化_1msecパルス生成

 「デジタル回路のスイッチ入力の同期化」でFPGAへスイッチの信号を入力することができました。次に時間を生成するブロックの設計に入ります。下記ブロックの黄色の部分です。

 このブロックは10MHzのクロック信号から1msecパルスを生成します。FPGAでは同期設計が主流ですので、同期設計で1msec周期のパルスを生成する回路になります。

 まず、1msec周期のパルス。というのが想像つくでしょうか? 1msecの方形波ではなく、10MHzクロックに同期した1msec周期のパルスなのでデジタル回路を初めて設計する方には馴染みの無い波形だと思います。具体的には次のような波形です。(表現上縮尺がめちゃくちゃです)

 1msec周期の方形波はデューティーが1:1です。しかし、いま欲しい波形は10MHzが1回だけHiになっていて、それ以外は全部Lowの波形です。ちょっと計算してみましょう。

 10MHz = 100nsec  … 周波数 ー> 周期変換

 1msec / 100nsec = 10000

 つまりデューティーで言うと1:9999の波形です。(あまりこのような波形をデュティーで示さないので、書いていて驚いています。上の波形は1:9999に見えませんね)

 このように1msecに1回100nsecのHiがある波形になります。このような波形を作り出すのが同期設計になります。これがクロック10MHzでなく、20MHzであれば、1msecに1回50nsecのHiがある波形を目指せば良いのです。

 デジタル回路の同期設計は、クロックの1つの幅を使って何かをする。という方法を頻繁に使います。

 たとえば、音楽のCDではサンプリング周波数が44.1kHzです。かといって、クロックが44.1kHzで動作しているCDプレーヤはほとんどありません。もっと周波数が高いクロックを使って、44.1kHz周期で動くようにしているのです。そうすることによって、計算が自由にできるようになるからです。よく聞くオーバーサンプリング回路のように44.1kHzに1回動かすのではなく、倍の88.2kHzで動かす。という事ができるようになるのです。

 話が前後してしまいましたが、なぜ1msecのパルスを生成するのでしょうか? 本当に欲しいパルスは10msecです。なので、10MHzから一気に10msecを作れば良いと思われます。これは、正解です。

 わざわざ1msecを作る必要はありません。10MHzから一気に10msecを作れます。たぶん・・・。では、試しに10msecを設計してみます。

 10msec / 100nsec(10MHz) = 100000

1msec->10msecになったのですから、10倍数えることになります。これをHexに変換してみます。

 100000 (dec) -> 186a0(hex)

  binとhexの関係が分かっていれば、この値が何ビットになるのかすぐにわかると思います。17bitですね。

 10MHzで17ビット数えることになります。デジタル回路のカウンタというのはビット数が増えれば増えるほど、上の桁(MSB)の繰り上がり時間が短くなります。カウンタとうのはHDLの記述を読めばわかりますが、数を+1しています。当然、1を足すので一番下の桁ですね。その桁に1を足せば、次の桁に桁上がりが生じて・・・っていうことを繰り返す必要があります。桁が上がれば上がるほど桁上がりの計算に時間がかかることになります。

 昔はFPGAでカウンタを設計するのに、何ビットのカウンタを何MHzで設計できます。という指標みたいな物がメーカーで公表していたのですが、最近はそんなことはしなくなりました。FPGAが優秀になってきたのと、FPGAの中の配置配線によって違いが出てしまうからです。

 昨今のFPGAでは100MHzで16ビットのカウンタなんて簡単に動いてしまいます。なので、今回の10MHzで17ビットのカウンタは余裕だと思います。この動く、動かない。というのは、FPGAの統合開発環境で設計をしてコンパイルをしてみると速度についてのレポートを出してくれます。そのレポートを読んで今回のカウンタが余裕をもって動いているのかを確認する必要があります。

 もうひとつ理由があります。それはFPGAの中でどの回路が重要なのかを見極める事です。今回の回路は正直言って、10msecだろうが、1msecだろうがそんなに精度を要求していません。時間的精度でいうと9.9msecでも何も変わりませんし、17ビットと15ビットの差が回路に影響を及ぼすほどシビアな訳でもありません。

 これは経験ですが、時間のタイミング回路。今回のように10msecとか1msecとかキレの良い時間というのは案外他の回路で使いたくなるモノです。したがって、10msecを作るのであれば、ついでに1msecがあっても悪いことはありません。

 このように、回路の重要度が低い回路をざわざわギリギリで設計すべきではないのです。全部の回路をギリギリで設計する方が見受けられますが、それはFPGAの消費電力も悪くなりますし、FPGAの中身が一杯になってきたときの配置配線に苦労することにつながります。

 それでは実際の1msecのパルスを生成する回路例を示します。

--  TITLE:					"Count1msec.vhd"
--  MODULE NAME:			
--  PROJECT CODE:			
--  AUTHOR:					 (****@nakaharagiken.com)
--  CREATION DATE:			2020.7.4
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
--  DESCRIPTION:            
--  NOTES TO USER:			入力10MHzで1msecのカウントパルス生成
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.1	2020.7.4	First edition
--
--							入力クロック 10MHz = 100nsec
--							出力パルス	1msec
--
--							1msec / 100nsec = 10000(dec) = 2710(hex)
--							15bitで数えても良いが16bitで設計した
--
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;


entity Count1msec is
port (
	clock:				in	std_logic;						-- system clock 10MHz
	nreset:				in	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
	tim1msec:			out	std_logic						-- 1msec信号						_______|~|_______________
);
end Count1msec;

architecture rtl of Count1msec is

---------------------------------------------------------------
-- SIGNALS
---------------------------------------------------------------
signal		rcounter:			std_logic_vector(15 downto 0);					-- カウンター
signal		rPls_out:			std_logic;										-- 出力用レジスタ

constant	c1MSEC:				std_logic_vector(15 downto 0) := X"270f";		-- 1msec / 100nsec

begin

------------------------------------------
-- カウンタ
------------------------------------------
process (clock,nreset) begin
	if nreset = '0' then									-- リセット初期化
		rcounter <= (others => '0');
		rPls_out <= '0';
	elsif clock' event and clock = '1' then					-- clock 立ち上がり指示
		if (rcounter = c1MSEC) then
			rPls_out <= '1';
			rcounter <= (others => '0');					-- reset counter 
		else
			rPls_out <= '0';
			rcounter <= rcounter +'1';
		end if;
	end if;
end process;

tim1msec <= rPls_out;

end architecture rtl;

//  TITLE:					"Count1msec.v"
//  MODULE NAME:			
//  PROJECT CODE:			
//  AUTHOR:					 (****@nakaharagiken.com)
//  CREATION DATE:			2020.7.4
//  SOURCE:            		
//  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
//  DESCRIPTION:            
//  NOTES TO USER:			入力10MHzで1msecのカウントパルス生成
//  SOURCE CONTROL:			
//  REVISION HISTORY:  	    v0.1	2020.7.4	First edition
//
//
//
//							入力クロック 10MHz = 100nsec
//							出力パルス	1msec
//
//							1msec / 100nsec = 10000(dec) = 2710(hex)
//							15bitで数えても良いが16bitで設計した
//
//
//
//
`timescale 1ns/1ps


module Count1msec (
	clock,							//	in	system clock 10MHz
	nreset,							//	in	asynchronous reset 				____reset___|~~~normal~~~
	tim1msec						//	out	1msec信号						_______|~|_______________
);


input	clock;						//	in	system clock 10MHz
input	nreset;						//	in	asynchronous reset 				____reset___|~~~normal~~~
output	tim1msec;					//	out	1msec信号						_______|~|_______________

///////////////////////////////////////////////////////////////
// SIGNALS
///////////////////////////////////////////////////////////////
reg			[15:0]	rcounter;				//	カウンター
reg					rPls_out;				//	出力用レジスタ

parameter	[15:0]	c1MSEC = 16'h270f;		//	1msec / 100nsec


//////////////////////////////////////////
// カウンタ
//////////////////////////////////////////
always @ (posedge  clock, negedge nreset) begin
	if (!nreset) begin
		rcounter <= 16'h0000;
		rPls_out <= 1'b0;
	end else begin
		if (rcounter == c1MSEC) begin
			rPls_out <= 1'b1;
			rcounter <= 0;					// reset counter 
		end else begin
			rPls_out <= 1'b0;
			rcounter <= rcounter + 1;
		end
	end
end

assign tim1msec = rPls_out;

endmodule

 VHDLとVerilogの両方で記載してみました。コメントにも記載していますが、10000(dec) = 2710(hex) ですので2710(hex)回数えれば良いのですが、0から数えているので、定数の宣言(VHDL42行目)で-1しています。

 VHDLの53行目がカウンタの心臓部です。54行目でカウンタの値がc1MSECになったときに、カウンタの値を0にクリアして、rPls_outをHiにしています。そして、59行目が+1づつカウントアップしている部分です。

 このようにHDLではカウンタは+1すれば良いだけです。回路的には難しくありません。カウンタの値をどうするのか? 止めるのか? クリアするのか? といった使い方で多少変わってきますが、今回は10MHzで数え続けていれば良いので停止も入っていません。

 今回のように+1するカウンタをアップカウンタといいます。逆に-1するカウンタをダウンカウンタといいます。どちらを使うのか迷うときにはアップカウンタを使いましょう。デジタル回路で引き算は結構苦手なのです。