---------------------------------------------------------------------------------- -- Engineer: Christoph Läubrich (mail@laeubi-soft.de) -- Create Date: 17:42:04 04/10/2009 -- Module Name: CHAR_LCD_CTR - Behavioral -- Description: 16x2 Text LCD controller for 8bit Mode -- used on the Spartan-3A Starter development board -- Free software, use at your own risk! ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity CHAR_LCD_CTR is Port ( clk_50M : in STD_LOGIC; --- LCD Interface --- -- 8 Bit data port -- LCDData : out STD_LOGIC_VECTOR (7 downto 0); -- LCD Enable Line -- LCD_Enable : out STD_LOGIC; -- LCD R/W Select line !will be forced low continuously! LCD_RW : out STD_LOGIC; -- Register Select Line LCD_RegisterSelect : out STD_LOGIC; --- Communication Interface --- -- high when init is done, low otherwhise -- init_done : out std_logic; -- Adress of character address : in std_logic_vector(4 downto 0); -- Character data -- data : in std_logic_vector(7 downto 0); -- Write strobe high = write data -- wr : in std_logic ); end CHAR_LCD_CTR; architecture Behavioral of CHAR_LCD_CTR is -- ############ Config Part ######################### -- Constant for 1 us or Clockrate in MHz constant one_us :integer := 50; -- Constant for Line 1 addressing constant line1 :STD_LOGIC_VECTOR (7 downto 0):= x"80"; -- Constant for Line 2 addressing constant line2 :STD_LOGIC_VECTOR (7 downto 0):= x"C0"; -- ############ Implement Part ####################### -- ############ change with care! #################### -- How many characters forms a line? -- Ram init has to be adjusted acordingly, -- as well as address width constant line_width :integer := 16; constant ram_deep :integer := 2*line_width; constant init_length:integer := 7; type ram_t is array (ram_deep-1 downto 0) of std_logic_vector(7 downto 0); type STATES is (INIT, WAITX, WRITE1, WRITE2, INITDONE, SETADDRESS, OUTPUTCHAR); -- Shaddow RAM signal char_ram : ram_t := ( -- [ ! e n o d x"5D", x"20", x"20", x"21", x"65", x"6E", x"6F", x"64", -- t i n I ] x"20", x"74", x"69", x"6E", x"49", x"20", x"20", x"5B", -- a b c d e f g h x"61", x"62", x"63", x"64", x"65", x"66", x"67", x"68", -- Init Sequence... -- 0x38 four times for 8-bit Mode -- 0x06 Set Entry Mode, No Display Shift, Increment cursor -- 0x0C Display Control, Blink off, Cursor off, Display on -- 0x01 Clear Display x"00", x"01", x"0C", x"06", x"38", x"38", x"38", x"38" ); signal state : STATES := INIT; signal next_wait : STATES; signal next_write : STATES; signal ram_count : integer range 0 to ram_deep-1 := 0; signal wait_counter : integer range 0 to 15000 := 0; signal us_counter : integer range 0 to one_us := one_us; signal line : std_logic := '0'; signal initd : std_logic := '0'; begin LCD_RW <= '0'; init_done <= initd; RAMCTR: process begin wait until rising_edge(clk_50m); if wr = '1' and initd = '1' then char_ram(conv_integer(address)) <= data; end if; end process; LCDCTR: process begin wait until rising_edge(clk_50m); case state is when INIT => initd <= '0'; LCD_Enable <= '0'; if ram_count = init_length then -- Init done... state <= INITDONE; else -- After wait we want write next_wait <= WRITE1; -- After write we want INIT next_write <= INIT; -- Next State is WAIT state <= WAITX; -- 15ms betwen each Init command wait_counter <= 15000; -- Read next Init Value LCDData <= char_ram(conv_integer(ram_count)); -- Increment init counter ram_count <= ram_count+1; -- Write to Command Register LCD_RegisterSelect <= '0'; end if; when WAITX => -- decrement us counter us_counter <= us_counter - 1; -- one us done? if us_counter = 0 then -- reset us counter us_counter <= one_us; -- decrement wait counter wait_counter <= wait_counter - 1; -- wait done? if wait_counter = 0 then -- change to next state state <= next_wait; end if; end if; when WRITE1 => -- set enable high LCD_Enable <= '1'; -- after wait we want WRITE2 next_wait <= WRITE2; -- next state is wait state <= WAITX; -- wait at least 1µS between enable pulse wait_counter <= 10; when WRITE2 => -- clear enable LCD_Enable <= '0'; -- wait atleast 40µS for command to complete wait_counter <= 400; -- goto next state next_wait <= next_write; state <= WAITX; when INITDONE => -- Wait another 2 ms wait_counter <= 2000; -- After wait goto SETADDRESS next_wait <= SETADDRESS; -- next state is wait... state <= WAITX; -- init line to zero line <= '0'; -- signalize that init is done initd <= '1'; when SETADDRESS => -- Line 1 or Line 2? if line = '0' then LCDData <= LINE1; ram_count <= 0; line <= '1'; else LCDData <= LINE2; ram_count <= line_width; line <= '0'; end if; -- Write to Command Register LCD_RegisterSelect <= '0'; -- After write switch to OUTPUTCHAR next_write <= OUTPUTCHAR; -- Next state is write state <= WRITE1; when OUTPUTCHAR => -- Wait 2 ms to prevent flickering wait_counter <= 2000; state <= WAITX; -- Output char LCDData <= char_ram(conv_integer(ram_count)); -- Write to Data Register LCD_RegisterSelect <= '1'; -- line done? if ram_count = ram_deep-1 or ram_count = line_width-1 then next_write <= SETADDRESS; else -- After write we want to output next char next_write <= OUTPUTCHAR; end if; -- After that goto write next_wait <= WRITE1; -- increment pointer ram_count <= ram_count + 1; end case; end process; end Behavioral;