(DE0-CV) DE0拡張キットのLCDモジュールを使う (4)
前
(DE0-CV) DE0拡張キットのLCDモジュールを使う (3)
VHDLにする
前回作成したタイミングチャートをVHDLにしました。
サンプルとしてQuartusのプロジェクトも置いておきます。
(Quartus Prime Version 16.1.0 Build 196 10/24/2016 SJ Lite Edition で確認)
DE0_CV_LCD.zip - Google ドライブ
library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_misc.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; entity DE0_CV_LCD is port( --//////////// CLOCK ////////// CLOCK_50 : in std_logic; CLOCK2_50 : in std_logic; CLOCK3_50 : in std_logic; CLOCK4_50 : inout std_logic; --//////////// KEY ////////// KEY : in std_logic_vector( 3 downto 0); RESET_N : in std_logic; --//////////// LED ////////// LEDR : out std_logic_vector( 9 downto 0); --//////////// for connecting an LCD ////////// LCD_D : out std_logic_vector( 7 downto 0); LCD_RS : out std_logic; LCD_RW : out std_logic; LCD_EN : out std_logic ); end DE0_CV_LCD; architecture RTL of DE0_CV_LCD is -------------------------------------------------- -- 初期化開始待機用信号 signal sWakeUpCounter : std_logic_vector(20 downto 0); signal sModuleEnable : std_logic; -------------------------------------------------- -------------------------------------------------- -- クロックカウント用信号 signal sClockCounter : std_logic_vector(17 downto 0); signal sMaxCount : std_logic_vector(sClockCounter'range); -------------------------------------------------- -------------------------------------------------- -- 状態カウント用信号 -- kStopStateまでsStateCountをカウントし続ける signal sStateCount : std_logic_vector( 4 downto 0); constant kStopState : std_logic_vector(sStateCount'range) := conv_std_logic_vector(20, sStateCount'length); -------------------------------------------------- -------------------------------------------------- -- sStateCountの値に対応したLCD_RS, LCD_RW, LCD_Dの出力 -- 2次元配列に格納している値をLCD_RS, LCD_RW, LCD_Dに割り当てる signal sCommandOfLCD : std_logic_vector( 9 downto 0); type tPatternOfLCD is array( 0 to 19) of std_logic_vector(sCommandOfLCD'range); constant kFunstionSet : std_logic_vector(sCommandOfLCD'range) := "0000111100"; constant kDisplayInit : std_logic_vector(sCommandOfLCD'range) := "0000001000"; constant kDisplayControl : std_logic_vector(sCommandOfLCD'range) := "0000001111"; constant kDisplayClear : std_logic_vector(sCommandOfLCD'range) := "0000000001"; constant kEntryModeSet : std_logic_vector(sCommandOfLCD'range) := "0000000110"; -- HELLO WORLD! の値 constant kH : std_logic_vector(sCommandOfLCD'range) := "1001001000"; constant kE : std_logic_vector(sCommandOfLCD'range) := "1001000101"; constant kL : std_logic_vector(sCommandOfLCD'range) := "1001001100"; constant kO : std_logic_vector(sCommandOfLCD'range) := "1001001111"; constant kSp : std_logic_vector(sCommandOfLCD'range) := "1000100000"; constant kW : std_logic_vector(sCommandOfLCD'range) := "1001010111"; constant kR : std_logic_vector(sCommandOfLCD'range) := "1001010010"; constant kD : std_logic_vector(sCommandOfLCD'range) := "1001000100"; constant kEx : std_logic_vector(sCommandOfLCD'range) := "1000100001"; constant kInitPattern : tPatternOfLCD := ( kFunstionSet, kFunstionSet , kFunstionSet , kFunstionSet , kDisplayInit, kDisplayClear, kEntryModeSet, kDisplayControl, kH , kE , kL , kL , kO , kSp , kW , kO , kR , kL , kD , kEx ); -------------------------------------------------- -------------------------------------------------- -- sStateCountの値に対応したEの周期 (t_cycE) -- 初期化処理やコマンドによって異なるため、 -- 2次元配列によってコマンドごとに時間を決めている type tWaitPatternOfLCD is array( 0 to 19) of std_logic_vector(sClockCounter'range); constant kWait4500us : std_logic_vector(sClockCounter'range) := "110110111011101000"; constant kWait200us : std_logic_vector(sClockCounter'range) := "000010011100010000"; constant kWait40us : std_logic_vector(sClockCounter'range) := "000000011111010000"; constant kInitWaitPattern : tWaitPatternOfLCD := ( kWait4500us , kWait200us , kWait40us, kWait40us, kWait40us , kWait4500us , kWait40us, kWait40us, kWait40us , kWait40us , kWait40us, kWait40us, kWait40us , kWait40us , kWait40us, kWait40us, kWait40us , kWait40us , kWait40us, kWait40us ); -------------------------------------------------- -------------------------------------------------- -- LCD_RS, LCD_RW開始/終了時間 constant kRsStart : std_logic_vector(sClockCounter'range) := conv_std_logic_vector( 0, sClockCounter'length); constant kRsEnd : std_logic_vector(sClockCounter'range) := conv_std_logic_vector(128, sClockCounter'length); -------------------------------------------------- -- LCD_EN開始/終了時間 constant kEnStart : std_logic_vector(sClockCounter'range) := conv_std_logic_vector( 32, sClockCounter'length); constant kEnEnd : std_logic_vector(sClockCounter'range) := conv_std_logic_vector( 96, sClockCounter'length); -------------------------------------------------- -- LCD_D開始/終了時間 constant kComStart : std_logic_vector(sClockCounter'range) := conv_std_logic_vector( 64, sClockCounter'length); constant kComEnd : std_logic_vector(sClockCounter'range) := conv_std_logic_vector(128, sClockCounter'length); -------------------------------------------------- begin -------------------------------------------------- -- 初期化処理待機用 process (CLOCK_50, RESET_N) is begin if RESET_N = '0' then sWakeUpCounter <= (others => '0'); elsif rising_edge(CLOCK_50) then -- sModuleEnable='0'の間、 -- sWakeUpCounterをカウントアップし続ける if (sModuleEnable = '0') then sWakeUpCounter <= sWakeUpCounter + '1'; end if; end if; end process; -- sWakeUpCounterがすべて'1'となったらsModuleEnable='1' sModuleEnable <= and_reduce(sWakeUpCounter); -------------------------------------------------- -------------------------------------------------- -- クロックカウント用 process (CLOCK_50, RESET_N) is begin if RESET_N = '0' then sClockCounter <= (others => '0'); elsif rising_edge(CLOCK_50) then if (sModuleEnable = '0' or sStateCount = kStopState) then -- 初期化待機中、もしくは状態が既定の値に達したら -- カウントアップを止める sClockCounter <= (others => '0'); elsif (sClockCounter = sMaxCount) then sClockCounter <= (others => '0'); else sClockCounter <= sClockCounter + '1'; end if; end if; end process; -- 各状態に対応したsClockCounterのMax値を代入 sMaxCount <= kInitWaitPattern(conv_integer(sStateCount)); -------------------------------------------------- -------------------------------------------------- -- 状態カウント用 process (CLOCK_50, RESET_N) is begin if RESET_N = '0' then sStateCount <= (others => '0'); elsif rising_edge(CLOCK_50) then if (sClockCounter = sMaxCount) then sStateCount <= sStateCount + '1'; end if; end if; end process; -------------------------------------------------- -------------------------------------------------- -- LCD_EN, LCD_D, LCD_RS, LCD_RW出力 process (CLOCK_50, RESET_N) is begin if RESET_N = '0' then LCD_EN <= '0'; elsif rising_edge(CLOCK_50) then if (sClockCounter > kEnStart and sClockCounter < kEnEnd) then LCD_EN <= '1'; else LCD_EN <= '0'; end if; end if; end process; process (CLOCK_50, RESET_N) is begin if RESET_N = '0' then LCD_D <= (others => '0'); elsif rising_edge(CLOCK_50) then if (sClockCounter > kComStart and sClockCounter < kComEnd) then LCD_D <= kInitPattern(conv_integer(sStateCount))( 7 downto 0); else LCD_D <= (others => '0'); end if; end if; end process; process (CLOCK_50, RESET_N) is begin if RESET_N = '0' then LCD_RW <= '0'; LCD_RS <= '0'; elsif rising_edge(CLOCK_50) then if (sClockCounter > kRsStart and sClockCounter < kRsEnd) then LCD_RW <= kInitPattern(conv_integer(sStateCount))(8); LCD_RS <= kInitPattern(conv_integer(sStateCount))(9); else LCD_RW <= '0'; LCD_RS <= '0'; end if; end if; end process; -------------------------------------------------- end architecture;