---------------------------------------------------------- -- LCD 2 lines controller -- -- 8 bits interface -- ---------------------------------------------------------- -- ESIEE -- Creation : A. Exertier, mars 2008 ---------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; ---------------------------------------------------------- -- INPUTS ---------------------------------------------------------- -- clk : system clock -- resetn : aynchronous active low reset -- en_250kHz : enable at 250 kHz (lasts 1 clock cycle) -- char : input ASCII character -- write_char : write character command -- ready : set to 1 when device is ready for a writing ---------------------------------------------------------- -- OUTPUTS ---------------------------------------------------------- -- LCD_DATA : ASCII data to LCD -- LCD_RS : RS to LCD -- LCD_RW : Read/write to LCD -- LCD_EN : Enable to LCD ------------------------------------------------------------ Entity LCD_controller is port( clk : in std_logic; resetn : in std_logic; en_250kHz : in std_logic; mode : in std_logic_vector(1 downto 0); char : in std_logic_vector (7 downto 0); address : in std_logic_vector(6 downto 0); write_char : in std_logic; write_address : in std_logic; ready : out std_logic; D : in std_logic; C : in std_logic; B : in std_logic; -- LCD signals LCD_data : inout std_logic_vector(7 downto 0); LCD_RS : out std_logic; LCD_RW : out std_logic; LCD_EN : out std_logic ); end LCD_Controller; Architecture RTL of LCD_Controller is type State_type is (Boot, FunctionSet, DisplayControl, EntryModeSet, Clear, Address_set, Waiting, Verify, Putchar, Homecursor, WriteAddress, WriteData); signal present : State_type; signal future : State_type; -- Timing Constants : constant T_30ms : integer := 30_000/4; -- 7500; -- 30 ms constant T_2ms : integer := 2_000/4; --500; -- 2 ms constant T_40us : integer := 12; -- > 39 us after E down constant En_delay : integer := 1; -- 8 us constant LastPosition : integer := 16; -- CLEAR DisplayControl constant CLR : std_logic_vector(7 downto 0) := "00000001"; -- RETURN HOME constant RET_HOME : std_logic_vector(7 downto 0) := "00000010"; -- 0000001x -- DDRAM address to 0 (beginning of first line) -- ENTRY MODE SET constant ENTRY_MODE : std_logic_vector(7 downto 0) := "00000110"; -- 0000 01 I/D S -- I/D : 1 => Increment, 0 => Decrement -- S : 1 => DisplayControl shift -- FUNCTION SET constant FUNC_SET : std_logic_vector(7 downto 0) := "00111100"; -- 001 DL N F xx -- DL : 1 => 8 bits, 0 => 4 bits -- N : 1 => 2 lines, 0 => 1 line -- F : 1 => 5x10 dots, 0 => 5x8 dots -- DisplayControl ON/OFF CONTROL constant DON : std_logic_vector(7 downto 0) := "00001110"; -- 0000 1 D C B -- D : 1 => Display on -- C : 1 => Cursor on -- B : 1 => Cursor blink on constant RET_LINE2 : std_logic_vector(7 downto 0) := "11000000"; -- set DDRAM address to 32 (beginning of second line) constant RET_LINE1 : std_logic_vector(7 downto 0) := "10000000"; -- set DDRAM address to 0 (beginning of first line) signal Position : natural range 0 to 2*LastPosition; signal Count : natural range 0 to T_30ms; signal inc_C : std_logic; signal cmd_P : std_logic_vector(1 downto 0); --signal reset_P : std_logic; signal test_EN : std_logic; signal test_T_40us : std_logic; begin LCD_RW <= '0'; process (Clk, resetn) begin if resetn = '0' then present <= Boot; position <= 0; count <= 0; elsif rising_edge(clk) then if en_250kHz = '1' then present <= future; if inc_C = '1' then count <= count+1; else count <= 0; end if; case cmd_P is when "00" => position <= 0; when "01" => if position >= 31 then position <= 0; else position <= position+1; end if; when "10" => if address(6 downto 4) = "000" then position <= to_integer(unsigned(address(3 downto 0))); elsif address(6 downto 4) = "100" then position <= to_integer(unsigned(address(3 downto 0)))+16; else position <= 0; end if; when others => null; end case; end if; end if; end process; test_EN <= '1' when Count = En_delay else '0'; test_T_40us <= '1' when count >= T_40us else '0'; process(present, Write_char, mode, write_address, count, Position,char, address,test_EN, test_T_40us , D, C, b) is begin future <= present; inc_C <= '1'; cmd_P <= "11"; ready <= '0'; LCD_RS <= '0'; LCD_EN <= '0'; LCD_data <= X"00"; case present is when Boot => -- Wait for 30 ms if Count = T_30ms then future <= FunctionSet; inc_C <= '0'; end if; cmd_P <= "00"; when FunctionSet => -- Function Set LCD_data <= FUNC_SET; LCD_EN <= test_EN; if test_T_40us = '1' then future <= EntryModeSet; inc_C <= '0'; end if; cmd_P <= "00"; when EntryModeSet => -- Entry Mode Set LCD_data <= ENTRY_MODE; LCD_EN <= test_EN; if test_T_40us = '1' then future <= DisplayControl; inc_C <= '0'; end if; cmd_P <= "00"; when DisplayControl => -- Display ON/OFF control LCD_data <= DON(7 downto 3)&D&C&B; LCD_EN <= test_EN; if test_T_40us = '1' then future <= Clear; inc_C <= '0'; end if; cmd_P <= "00"; when Clear => -- Clear Display LCD_data <= CLR; LCD_EN <= test_EN; if Count >= T_2ms then inc_C <= '0'; future <= Address_set; end if; cmd_P <= "00"; when Address_set => -- DDRAM address set LCD_data <= RET_LINE1; LCD_EN <= test_EN; if test_T_40us = '1' then future <= Waiting; inc_C <= '0'; end if; cmd_P <= "00"; when Waiting => -- Waits for input if mode (1) = '1' then if write_address = '1' then future <= WriteAddress; elsif write_char = '1' then future <= WriteData; end if; elsif write_char = '1' then if char = x"0C" then future <= Clear; else future <= Putchar; end if; end if; ready <= '1'; inc_C <= '0'; when WriteAddress => -- Set CGRAM/DDRAM Address if mode(0) = '0' then LCD_data <= '1'&address; else LCD_data <= "01"&address(5 downto 0); end if; LCD_EN <= test_EN; if test_T_40us = '1' then future <= Waiting; inc_C <= '0'; end if; cmd_P <= "10"; when WriteData => -- Write data to CGRAM or DDRAM LCD_RS <= '1'; LCD_EN <= test_EN; LCD_DATA <= char; if test_T_40us = '1' then future <= Waiting; inc_C <= '0'; cmd_P <= "01"; end if; when Verify => if char = x"0C" then -- FormFeed => Clear Screen future <= Clear; else future <= Putchar; end if; inc_C <= '0'; LCD_data <= char; when Putchar => -- Display character on the LCD LCD_RS <= '1'; LCD_EN <= test_EN; if test_T_40us = '1' then if Position = 15 or Position = 31 then future <= HomeCursor; else future <= Waiting; cmd_P <= "01"; end if; inc_C <= '0'; end if; LCD_data <= char; when HomeCursor => LCD_EN <= test_EN; if Position = 31 then LCD_data <= RET_LINE1; --RET_HOME; else LCD_data <= RET_LINE2; end if; if test_T_40us = '1' then --if Count >= T_2ms then if Position = 31 then cmd_P <= "00"; else cmd_P <= "01"; end if; future <= Waiting; inc_C <= '0'; end if; end case; end process; end RTL;