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クロック遅れていると思います。

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