FPGA MAX10(9)-ポーリング処理とエッジ検出処理

プッシュスイッチを押すとトグルスイッチで指定した数値をSPI通信で送信、受信を行い、7セグメントに表示することができました。

FPGA MAX10(8)-SPI通信

ただし、今回作成した機能はプッシュスイッチのところに課題があります。シグナルタップアナライザで確認してみると下記のように出力されました。

プッシュスイッチを少し押しただけであるが、プッシュスイッチ(SET_N)が押し続けている状態になっています。FPGAとしては、10MHz(100nsec)クロックで動作しているので、スイッチは押し続けていると判定されてしまいます。そのため、一度送信すればよい数値データを繰り返し送信してしまっています。

そこで、エッジ検出が必要となってきます。今回は、前回作成したSPI通信の機能に、エッジ検出を追加ししたいと思います。合わせてチャタリング除去のためにポーリング処理も追加したいと思います。具体的には下記のようにエッジ検出処理とポーリング処理機能を構築します。

  • プッシュスイッチが100msec毎に押されているかどうか判定する。
  • 2回スイッチが押されていると判定された場合、FF(フリップフロップ)にその情報に「1」を入力する。
  • もう一つFFを用意しておき、こちらには前回の値を保存しておく。
  • 前回の値が「0」、且つ、今回の値が「1」の場合、エッジ検出信号を「1」にする。

エッジ検出処理とポーリング処理機能を構築していきたいと思います。下記のようなモジュールを用意します。

FPGA MAX10(8)-SPI通信

7セグメントの出力部分が、出力先と条件以外はほぼ同じような記述がされているので、この部分をモジュールで作成してトップのVHDLファイルから呼び出すように改良をしました。機能ごとにファイルを分けることで、VHDLファイルが整理できました。

前回の内容は下記を参照してください。

FPGA MAX10(7)-モジュールのインスタンス化

今回は、SPI通信の回路を構築したいと思います。SPI通信は、クロック同期式のシリアル通信です。SPI通信では、下記のような4つのピンを使用します。

  • クロック(SPI CLK、SCLK)
  • チップセレクト(CS)
  • マスタ出力-スレーブ入力(MOSI)
  • マスタ入力-スレーブ出力(MISO)

MOSI、MOSOをSDO、SDIで表記している場合もあります。SPI通信は1つのマスタに対し、複数のスレーブを接続することができます。どのスレーブと通信するかはチップセレクタで選択します。

以前、SPI通信を使用して、RXマイコンでDACを制御しました。

RX(7)-SPI通信によるDAC制御

この時は、MOSIは使用しましたが、MISOは使用していないと思います。このように3ピンのみ使用して通信する場合もあります。

今回は、プッシュスイッチを押すと、トグルスイッチで指定した数値をSPI通信で送信します。受信したら、その数値を7セグメントで表示する機能を構築したいと思います。2つの評価ボードがあれば、通信している感じがあり、よりよいのですが、今回は1つの評価ボード上で、自ら送信を行い、自ら受信する機能を構築します。もう少し具体的に機能を考えると下記のようになります。

  • トグルスイッチを4つ使用して、0~9を指定できるようする。10~16の時は、0として扱います。
  • プッシュスイッチを押すと、トグルスイッチで指定した数値をSPI通信で送信する。
  • SPI通信で送信されたデータを受信する。
  • 受信した数値をを7セグメントに表示する。

それでは、機能を構築していきたいと思います。まずは新規プロジェクトを作成します。新規プロジェクトを作成できたら、IPを使用してPLL回路を追加します。PLLでは50MHzのクロックを入力として、10MHzのクロックを出力します。新規プロジェクトの作成方法、PLLの追加方法は下記のリンクを参照してください。

FPGA MAX10(4)-LEDシフト点灯回路

次に、VHDLファイルに動作内容を記述していきます。まずは、SPI通信の送信機能のモジュールを構築します。この送信機能は今回マスター側にもたせます。

FPGA MAX10(7)-モジュールのインスタンス化

前回は、DE10-Lite評価ボードを使用して、24時間をカウントする機能を改良しまじた。機能的には問題ないと思いますが、1カウンタ早く処理をするように改善したいので改良を行いました。

前回の内容は下記を参照してください

FPGA MAX10(6)-24時間カウンタ回路②

前回の内容ですが、7セグメントの出力部分が、出力先と条件以外はほぼ同じような記述がされています。この部分を関数のように処理ができると思うので前回作成した24時間カウンタ機能のVHDLファイルを改良したいと思います。

24時間カウンタ機能の仕様は下記の通りです。

  • DE10-Liteには、7セグメントが6個用意されています。
  • その中の2個ずつを、秒、分、時に割り当てます。
  • Resetボタンを押すと、00時00分00秒になります。
  • 24時間になった場合、00時00分00秒になります。

それでは、改良していきたいと思います。前回のプロジェクトファイルを開いて、新規VHDLファイルを追加、下記のようにコードを記述して、7セグメントに数値を表示するモジュールを作成しました。

FPGA MAX10(6)-24時間カウンタ回路②

前回に、DE10-Lite評価ボードを使用して、4時間をカウントする機能を作成しました。前回の内容は下記を参照してください。

FPGA MAX10(5)-24時間カウンタ回路①

24時間カウンタ機能の仕様は下記の通りです。

  • DE10-Liteには、7セグメントが6個用意されています。
  • その中の2個ずつを、秒、分、時に割り当てます。
  • Resetボタンを押すと、00時00分00秒になります。
  • 24時間になった場合、00時00分00秒になります。

今回は、DE10-Lite評価ボードを使用して、24時間をカウントする機能を改良していきたいと思います。今回も使用する言語は、VHDLです。前回述べたのように、機能的には問題ないと思いますが、カウンタのズレが発生していると思います。

例えば、7セグメントに信号を送る処理をprocess処理のcase文で行っていますが、ここもカウンタが更新されて1クロック遅れて更新されていると思いわれます。下記のように回路図でみるとレジスタから出力されています。そのため、1クロック遅れていると思います。

今回は、ここらへん内容を改良していきたいと思います。それでは、改良していきたいと思います。

前回のプロジェクトファイルを開いて、下記のようにVHDLファイルを改良しました。

FPGA MAX10(5)-24時間カウンタ回路①

前回に、DE10-Lite評価ボードを使用して、LEDの点灯をシフトする機能を作成しました。前々回の内容は下記を参照してください。

FPGA MAX10(4)-LEDシフト点灯回路

今回は、DE10-Lite評価ボードを使用して、24時間をカウントする機能を
構築したいと思います。今回も使用する言語は、VHDLです。

24時間カウンタ機能の仕様は下記の通りです。

  • DE10-Liteには、7セグメントが6個用意されています。その中の2個ずつを、秒、分、時に割り当てます。
  • Resetボタンを押すと、00時00分00秒になります。
  • 24時間になった場合、00時00分00秒になります。

それでは、機能を構築していきたいと思います。前回使用したプロジェクトをコピーして使用します。前回の内容は、下記のリンクを参考にしてください。PLLファイルの生成なども行っています。

FPGA MAX10(4)-LEDシフト点灯回路

クロックはPLLで生成した「10MHz」を使用します。VHDLファイルに動作内容を記述していきます。下記のように記述しました。

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity sec_counter_top is	-- Output pin
	port(
		CLK			: in  std_logic;  -- 50MHz Clock
		RST_N			: in  std_logic;
		LED_OUT		: out std_logic_vector(9 downto 0);
		SEG7_0_OUT	: out std_logic_vector(7 downto 0);
		SEG7_1_OUT	: out std_logic_vector(7 downto 0);
		SEG7_2_OUT	: out std_logic_vector(7 downto 0);
		SEG7_3_OUT	: out std_logic_vector(7 downto 0);
		SEG7_4_OUT	: out std_logic_vector(7 downto 0);
		SEG7_5_OUT	: out std_logic_vector(7 downto 0)
	);
end sec_counter_top;

architecture rtl of sec_counter_top is -- Internal process

	component pll is -- pll
		port(
			inclk0	: in  std_logic;	-- 50MHz Clock
			c0			: out std_logic	-- 10MHz Clock
		);
	end component;

	signal s_clk			: std_logic;	-- 10MHz Clock signal
	signal en_sec_1     	: std_logic;
	signal en_min_1     	: std_logic;
	signal en_hour_1    	: std_logic;
	signal en_sec_10    	: std_logic;
	signal en_min_10    	: std_logic;
	signal en_hour_10   	: std_logic;
	signal en_hour_flg  	: std_logic_vector(3 downto 0);
	signal cnt 				: std_logic_vector(23 downto 0);
	signal sec_1_cnt 		: std_logic_vector(3 downto 0);
	signal min_1_cnt 		: std_logic_vector(3 downto 0);
	signal hour_1_cnt 	: std_logic_vector(3 downto 0);
	signal min_10_cnt 	: std_logic_vector(3 downto 0);
	signal sec_10_cnt 	: std_logic_vector(3 downto 0);
	signal hour_10_cnt 	: std_logic_vector(3 downto 0);
	signal counter_led	: std_logic_vector(9 downto 0);

	begin

		u0_pll : pll
			port map(
				inclk0	=> CLK, --in  std_logic(50MHz)
				c0			=> s_clk --out std_logic(10MHz)
			);
		
		-- 1 sec
--		en_sec_1 <= '1' when (cnt = X"AD9") else '0'; -- 1 / 3600 sec
		en_sec_1 <= '1' when (cnt = X"989659") else '0'; -- 1 sec

		process(s_clk, RST_N) -- s_clkに変化があった時
			begin
				if(RST_N = '0')then
					cnt <= (others=>'0');
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_sec_1 = '1')then
						cnt <= (others=>'0');
					else
						cnt <= cnt + '1';
					end if;
				end if;
		end process;
		
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
					sec_1_cnt <= X"0";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_sec_1 = '1')then
						sec_1_cnt <= sec_1_cnt + '1';
					else
						if(sec_1_cnt = X"A")then
							sec_1_cnt <= X"0";
						end if;
					end if;
				end if;
		end process;
		
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
					SEG7_0_OUT <= "11000000"; 
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					case sec_1_cnt is
						when X"1" =>
							SEG7_0_OUT <= "11111001";
						when X"2" =>
							SEG7_0_OUT <= "10100100";
						when X"3" =>
							SEG7_0_OUT <= "10110000";
						when X"4" =>
							SEG7_0_OUT <= "10011001";
						when X"5" =>
							SEG7_0_OUT <= "10010010";
						when X"6" =>
							SEG7_0_OUT <= "10000010";
						when X"7" =>
							SEG7_0_OUT <= "11011000";
						when X"8" =>
							SEG7_0_OUT <= "10000000";
						when X"9" =>
							SEG7_0_OUT <= "10011000"; 
						when others =>
							SEG7_0_OUT <= "11000000"; 
					end case;
				end if;
		end process;
		
		-- 10 sec
		en_sec_10 <= '1' when (sec_1_cnt = X"A") else '0'; -- 10 sec	

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					sec_10_cnt <= X"5";
					sec_10_cnt <= X"0";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_sec_10 = '1')then
						sec_10_cnt <= sec_10_cnt + '1';
					else
						if(sec_10_cnt = X"6")then
							sec_10_cnt <= X"0";
						end if;
					end if;
				end if;
		end process;

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					SEG7_1_OUT <= "10010010"; 
					SEG7_1_OUT <= "11000000"; 
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					case sec_10_cnt is
						when X"1" =>
							SEG7_1_OUT <= "11111001";
						when X"2" =>
							SEG7_1_OUT <= "10100100";
						when X"3" =>
							SEG7_1_OUT <= "10110000";
						when X"4" =>
							SEG7_1_OUT <= "10011001";
						when X"5" =>
							SEG7_1_OUT <= "10010010"; 
						when others =>
							SEG7_1_OUT <= "11000000"; 
					end case;
				end if;
		end process;
		
		
		-- 1 min
		en_min_1 <= '1' when (sec_10_cnt = X"6") else '0'; -- 1 min
		
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					min_1_cnt <= X"9";
					min_1_cnt <= X"0";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_min_1 = '1')then
						min_1_cnt <= min_1_cnt + '1';
					else
						if(min_1_cnt = X"A")then
							min_1_cnt <= X"0";
						end if;
					end if;
				end if;
		end process;

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					SEG7_2_OUT <= "10011000"; 
					SEG7_2_OUT <= "11000000"; 
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					case min_1_cnt is
						when X"1" =>
							SEG7_2_OUT <= "11111001";
						when X"2" =>
							SEG7_2_OUT <= "10100100";
						when X"3" =>
							SEG7_2_OUT <= "10110000";
						when X"4" =>
							SEG7_2_OUT <= "10011001";
						when X"5" =>
							SEG7_2_OUT <= "10010010";
						when X"6" =>
							SEG7_2_OUT <= "10000010";
						when X"7" =>
							SEG7_2_OUT <= "11011000";
						when X"8" =>
							SEG7_2_OUT <= "10000000";
						when X"9" =>
							SEG7_2_OUT <= "10011000"; 	
						when others =>
							SEG7_2_OUT <= "11000000"; 
					end case;
				end if;
		end process;
		
		-- 10 min
		en_min_10 <= '1' when (min_1_cnt = X"A") else '0'; -- 10 min
		
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					min_10_cnt <= X"5";
					min_10_cnt <= X"0";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_min_10 = '1')then
						min_10_cnt <= min_10_cnt + '1';
					else
						if(min_10_cnt = X"6")then
							min_10_cnt <= X"0";
						end if;
					end if;
				end if;
		end process;

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					SEG7_3_OUT <= "10010010"; 
					SEG7_3_OUT <= "11000000"; 
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					case min_10_cnt is
						when X"1" =>
							SEG7_3_OUT <= "11111001";
						when X"2" =>
							SEG7_3_OUT <= "10100100";
						when X"3" =>
							SEG7_3_OUT <= "10110000";
						when X"4" =>
							SEG7_3_OUT <= "10011001";
						when X"5" =>
							SEG7_3_OUT <= "10010010";
						when others =>
							SEG7_3_OUT <= "11000000"; 
					end case;
				end if;
		end process;
		
		-- 1 hour
		en_hour_1 <= '1' when (min_10_cnt = X"6") else '0'; -- 1 hour
		
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					hour_1_cnt <= X"9";
					hour_1_cnt <= X"0";
					en_hour_flg <= X"F";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_hour_1 = '1')then
						hour_1_cnt <= hour_1_cnt + '1';
						en_hour_flg <= X"E";
					elsif(en_hour_flg = X"E")then
						if(hour_10_cnt = X"2")then
							if(hour_1_cnt = X"4")then
								en_hour_flg <= X"4";
							end if;
						else
							if(hour_1_cnt = X"A")then
								en_hour_flg <= X"A";
							end if;
						end if;
					else
						if(en_hour_flg = X"4")then
							hour_1_cnt <= X"0";
							en_hour_flg <= X"F";
						elsif(en_hour_flg = X"A")then
							hour_1_cnt <= X"0";
							en_hour_flg <= X"F";
						end if;
					end if;
				end if;
		end process;

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					SEG7_4_OUT <= "10011000"; 
					SEG7_4_OUT <= "11000000"; 
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					case hour_1_cnt is
						when X"1" =>
							SEG7_4_OUT <= "11111001";
						when X"2" =>
							SEG7_4_OUT <= "10100100";
						when X"3" =>
							SEG7_4_OUT <= "10110000";
						when X"4" =>
							SEG7_4_OUT <= "10011001";
						when X"5" =>
							SEG7_4_OUT <= "10010010";
						when X"6" =>
							SEG7_4_OUT <= "10000010";
						when X"7" =>
							SEG7_4_OUT <= "11011000";
						when X"8" =>
							SEG7_4_OUT <= "10000000";
						when X"9" =>
							SEG7_4_OUT <= "10011000"; 
						when others =>
							SEG7_4_OUT <= "11000000"; 
					end case;
				end if;
		end process;	
		
		-- 10 hour
		en_hour_10 <= '1' when (hour_1_cnt = en_hour_flg) else '0'; -- 10 hour

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					hour_10_cnt <= X"1";
					hour_10_cnt <= X"0";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_hour_10 = '1')then
						hour_10_cnt <= hour_10_cnt + '1';
					else
						if(hour_10_cnt = X"3")then
							hour_10_cnt <= X"0";
						end if;
					end if;
				end if;
		end process;

		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
--					SEG7_5_OUT <= "11111001"; 
					SEG7_5_OUT <= "11000000"; 
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					case hour_10_cnt is
						when X"1" =>
							SEG7_5_OUT <= "11111001";
						when X"2" =>
							SEG7_5_OUT <= "10100100"; 
						when others =>
							SEG7_5_OUT <= "11000000"; 
					end case;
				end if;
		end process;
		
		-- 1sec blink led
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
					counter_led <= "0000000001";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en_sec_1 = '1')then
						counter_led(1) <= counter_led(0);
						counter_led(2) <= counter_led(1);
						counter_led(3) <= counter_led(2);
						counter_led(4) <= counter_led(3);
						counter_led(5) <= counter_led(4);
						counter_led(6) <= counter_led(5);
						counter_led(7) <= counter_led(6);
						counter_led(8) <= counter_led(7);
						counter_led(9) <= counter_led(8);
						counter_led(0) <= counter_led(9);
					end if;
				end if;
		end process;
		
		LED_OUT <= counter_led;
		
end rtl;

次に、Tasksから「Compile Design」をダブルクリックして実行します。(「Analysis & Synthesis」のみ実行してもよいと思います。)

「Compile Design」が成功したら、ピンの設定をします。メニューから「Assignments」→「Pin Planner」を選択します。ピンの設定を行う画面が表示されるので、下記のようにピンを設定します。

その他に関しては、下記のサイトと同様です。

FPGA MAX10(4)-LEDシフト点灯回路

それでは、再度、Tasksから「Compile Design」をダブルクリックして実行します。「Compile Design」が成功したら、書き込みを行い、実行します。書き込み方法は下記のサイト参考にしてください。

FPGA MAX10(4)-LEDシフト点灯回路

書き込みを行い、実行すると7セグメントが動作していています。動作確認をするにあたって24時間DE10-Liteを見るのはつらいので、KEY0ボタンを押した時のリセット値や1秒間のカウンタの値を調整して動作確認をしました。

例えば、下記のようにすれば、時間の7セグメントを1秒間隔で動作することができます。

今回、24時間カウンタを作成しましたが、目視では確認できないですが、カウンタのズレが発生していると思います。例えば下記の部分がそうです。

24時間経過後に、00時間になりますが、時間の1の位が2クロック遅れて、0になります。秒の部分がズレてはいないので、全体的に遅れが生じることはないと思いますが、うーんって感じです。もう少し遅れが生じないような仕組みを考えたいところです。

また、7セグメントに信号を送る処理をprocess処理のcase文で行っていますが、ここもカウンタが更新されて1クロック遅れて更新されていると思いわれます。下記のように回路図でみるとレジスタから出力されています。そのため、1クロック遅れていると思います。

目視でみて問題ないような内容ではありますが、ここも見直したいと思います

FPGA MAX10(4)-LEDシフト点灯回路

前々回に、下記のFPGA(MAX10)基板を使用して、LEDの点滅回路を作成しました。

マルツ MAX10-FB(FPGA)基板 全実装版 【MTG-MAX10-FB-F】

新品価格
¥8,445から
(2021/2/13 23:06時点)

マルツ MAX10-JB(JTAG)基板 全実装版 【MTG-MAX10-JB-F】

新品価格
¥4,210から
(2021/2/13 23:07時点)

前々回の内容は下記を参照してください。

FPGA MAX10(2)-LED点滅回路

今回は、DE10-Lite評価ボードを使用して、LEDの点灯をシフトする機能を作成しようと思います。前々回はVerilog HDL言語を使用していましたが、今回はVHDL言語を使用したいと思います。

LED点灯シフト機能の使用は下記の通りで、シンプルです。

  • DE10-Liteには、赤色LEDが10個(LED0~LED9)が用意されています。 1秒経過するごとに、LED0→LED1→・・・→LED8→LED9→LED0→・・・変化させます。
  • DE10-LiteにはPushSwitchが2個(KEY0、KEY1)が用意されています。KEY0ボタンを押すと、LED0が点灯するようなリセット動作をします。
  • クロックカウンタもリセットさせます。

それでは、機能を構築していきたいと思います。まずは、新規プロジェクトを作成します。メニューから「File」→「New Project Wizard」を選択します。

下記のような画面が表示されるので、プロジェクトの保存先、プロジェクト名、トップエンティティ名をを入力して、「Next」ボタンを押します。

下記のような画面が表示されるので、プロジェクトタイプを選択します。今回は、Empty projectを選択して、「Next」ボタンを押します。

下記のような画面が表示されるので、追加したいファイルを選択します。今回は追加ファイルはないので、そのまま「Next」ボタンを押します。

下記のような画面が表示されるので、使用するFPGAを選びます。DE10-Liteには、「10M50DAF484C7G」が搭載されているので、「Available devices:」から選択して、「Next」ボタンを押します。

下記のような画面が表示されるので、EDAツールの設定を行います。今回はとくに設定は行わないので、そのまま「Next」ボタンを押します。

下記のような画面が表示されるので、設定した内容を確認して問題なければ、「Finish」ボタンを押します。

これでプロジェクトファイルの作成が完了したので、次にVHDLファイルを追加します。メニューから「File」→「New」を選択します。

下記のようが画面が表示されるので、「VHDL File」を選択して、「OK」ボタンを押します。

VHDLファイルが作成できたので、ファイルから「File」→「Save As」を選択して、名前を付け保存します。

ファイル名を入力(任意名)して、「保存」ボタンを押します。

クロックの設定を行っていきます。DE10-Liteのクロックは下記のようになっています。クロックジェネレータから生成されたクロックがMAX10に供給されています。今回、P11に供給されるクロックを使用しようと思います。50MHzになりますが、今回は、PLLで10MHzを生成して使用しようと思います。

今度は、IPを使用して、PLLを追加します。IP Catalogから「Installed IP」→「Library」→「Basic Functions」→「Clocks; PLLs and Resets」→「PLL」→「ATLPLL」を選択します。

下記のような画面が表示されるので、生成されるIPのファイル名を設定します。ファイルタイプは「VHDL」を選択してOKボタンを押します。

ALTPLLのウィーザードが表示されました。ウィザードに従って設定をしていきます。「What’s the frequency of the inclk0 input?」に「50.000MHz」を入力して、「Next」ボタンを押します。

「Create an ‘areset’ input to asynchronously reset the PLL」にチェックを入れて「Next」ボタンを押します。

「Output Clocks」のタブになるまで「Next」ボタンを押していきます。c0の設定画面が開かれたら、「Use this clock」にチェックを入れて、c0を有効にします。「Enter output clock frequency」にチェックを入れて、「10.000MHz」を入力して、「Next」ボタンを押します。

「Summary」のタブになるまで「Next」ボタンを押していきます。「Summary」が開かれたら、「pll.cmp」「pll_inst.vhd」を選択して「Finish」ボタンを押します。

プロジェクトにIPを追加したいですかと問われているので、「Yes」ボタンを押します。

これでPLLが追加されたので、それでは、先程新規作成したVHDLファイルに動作内容を記述していきます。下記のように記述しました。

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity de10lite_blink_top is	-- Output pin
	port(
		CLK		: in  std_logic;  -- 50MHz Clock
		RST_N		: in  std_logic;
		LED_OUT	: out std_logic_vector(9 downto 0)
	);
end de10lite_blink_top;

architecture rtl of de10lite_blink_top is -- Internal process

	component pll is -- pll
		port(
			inclk0	: in  std_logic;	-- 50MHz Clock
			c0			: out std_logic	-- 10MHz Clock
		);
	end component;

	signal s_clk			: std_logic;	-- 10MHz Clock signal
	signal en     			: std_logic;
	signal cnt 				: std_logic_vector(23 downto 0);
	signal counter_led	: std_logic_vector(9 downto 0);

	begin

		u0_pll : pll
			port map(
				inclk0	=> CLK, --in  std_logic(50MHz)
				c0			=> s_clk --out std_logic(10MHz)
			);
		
		en <= '1' when (cnt = X"989680") else '0'; -- 1sec

		process(s_clk, RST_N) -- s_clkに変化があった時
			begin
				if(RST_N = '0')then
					cnt <= (others=>'0'); -- cnt全部「0」※othersはそれ以外の意
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en = '1')then	-- 1msec
						cnt <= (others=>'0'); -- cnt全部「0」※othersはそれ以外の意
					else
						cnt <= cnt + '1';
					end if;
				end if;
		end process;
		
		process(s_clk, RST_N)
			begin
				if(RST_N = '0')then
					counter_led <= "0000000001";
				elsif(s_clk'event and s_clk = '1')then -- s_clk 変化有り 且つ s_clk = 1の時 →クロックの立ち上がりエッジ
					if(en = '1')then
						counter_led(1) <= counter_led(0);
						counter_led(2) <= counter_led(1);
						counter_led(3) <= counter_led(2);
						counter_led(4) <= counter_led(3);
						counter_led(5) <= counter_led(4);
						counter_led(6) <= counter_led(5);
						counter_led(7) <= counter_led(6);
						counter_led(8) <= counter_led(7);
						counter_led(9) <= counter_led(8);
						counter_led(0) <= counter_led(9);
					end if;
				end if;
		end process;
		
		LED_OUT <= counter_led;

		
end rtl;

次に、Tasksから「Compile Design」をダブルクリックして実行します。(「Analysis & Synthesis」のみ実行してもよいと思います。)

「Compile Design」が成功したら、ピンの設定をします。メニューから「Assignments」→「Pin Planner」を選択します。ピンの設定を行う画面が表示されるので、下記のようにピンを設定します

それでは、再度、Tasksから「Compile Design」をダブルクリックして実行します。「Compile Design」が成功したら、書き込みを行います。メニューから「Tools」→「Programmer」を選択します。下記のような画面が表示されるので、「Hardware Setup」ボタンを押します。

「Currently selected hardware」より「USB-Blaster[USB-*」を選択します。選択したら「Close」ボタンを押します。

「Start」ボタンを押して書き込みを行います。

1秒経過するごとに、LED0→LED1→・・・→LED8→LED9→LED0→・・・とLEDがシフトして点灯しています。KEY0ボタンを押すと、LED0が点灯しました。