Timing problem with HD44780 LCD controller on FPGA using VHDL

Joined
Jun 3, 2010
Messages
14
Reaction score
0
Hi

I made an HD44780 LCD controller for a DE2-70 development board. According to the datasheet for the HD44780, it appears the max operating frequency is limited by T_enable_cycle of 500ns (or 2MHz). When I run my code the fastest enable period I can run is roughly 2us or 500kHz without it behaving erratically(delay_500ns count = 100, not my intended 25). For instance, if I try to go any faster than 500kHz, it misses characters or shifts the letters to random positions on the screen. Also there's an unintended space in the beginning(in addition to my first space) which I can't figure out how to get rid of.

Does anyone have any idea what might be wrong?

Also I'm rather new to VHDL so this might not be the coded the best. If anyone has any tips or pointers or see any areas of improvement please let me know!

Thanks!

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity HD44780_controller is
port (clk		: in std_logic;
	  reset		: in std_logic := '1';
	  pb		: in std_logic := '1';
	  lcd_on	: out std_logic := '1';
	  en		: out std_logic := '0';
	  rs		: out std_logic := '0';
	  rw		: out std_logic := '0';
--	  bf 		: out std_logic := '0';
	  db		: inout std_logic_vector (7 downto 0));  -- inout
end HD44780_controller;

architecture arch of HD44780_controller is
	type state_type is (init, disp_on, wr_ddram, clr_disp, en_h, chk_bf, home);
	signal state, next_state : state_type;
	constant delay_15ms 	 : integer := 750000;  -- 750000
	constant delay_4ms 		 : integer := 205000;  -- 205000
	constant delay_100us 	 : integer := 5000;  -- 5000
	constant delay_40ns 	 : integer := 1;  -- 1
	constant delay_240ns 	 : integer := 12; -- 12
	constant delay_500ns 	 : integer := 100; -- 24 (100?)
	signal delay_count  	 : unsigned(19 downto 0);
	signal init_cmd 		 : unsigned(2 downto 0);
	SUBTYPE ascii IS STD_LOGIC_VECTOR(7 DOWNTO 0);
	TYPE charArray IS array(1 to 16) OF ascii;
	CONSTANT line1: charArray := (x"20",x"46",x"50",x"47",x"41",x"20",x"52",x"4F",x"43",x"4B",x"60",x"53",x"20",x"20",x"20",x"20");
	signal count 			 : integer := 0; --  unsigned(3 downto 0) := "0001";
	signal check_bf_f		 : std_logic;
	signal rw_reg			 : std_logic;
	signal db_in, db_out	 : std_logic_vector (7 downto 0);
	
begin

--================================================
-- outputs
--================================================
lcd_on <= '1';
rw <= rw_reg;
db <= db_out when rw_reg = '0' else (others => 'Z');  -- write: rw ='0', read: rw = '1' 
db_in <= db;
	   
process (clk, reset, delay_count, init_cmd, state, check_bf_f, db_in)
begin
	if reset = '0' then
		delay_count <= (others => '0');
		init_cmd <= (others => '0');
		count <= 0;
		db_out <= (others => '0');
		en <= '0';
		rs <= '0';
		rw_reg <= '0';
		state <= init;
		next_state <= init;
	elsif clk'event and clk = '1' then
		delay_count <= delay_count + 1;
		en <= '0';
		case state is
--================================================
-- power up
--================================================
			when init =>
				check_bf_f <= '0';
				rs <= '0';
				rw_reg <= '0';
				if (delay_count = delay_15ms and init_cmd = "000") then  -- delay_15ms --4
					delay_count <= (others => '0');
					check_bf_f <= '1';
					init_cmd <= init_cmd + 1;
					db_out <= x"38";
					state <= en_h;
					next_state <= init;
				elsif (delay_count = delay_4ms and init_cmd = "001") then  -- delay_4ms -- 2
					delay_count <= (others => '0');
					check_bf_f <= '1';
					init_cmd <= init_cmd + 1;
					db_out <= x"38";
					state <= en_h;
					next_state <= init;
				elsif (delay_count = delay_100us and init_cmd = "010") then  -- delay_100us -- 1
					delay_count <= (others => '0');
					check_bf_f <= '1';
					init_cmd <= init_cmd + 1;
					db_out <= x"38";
					state <= en_h;
					next_state <= init;
				elsif (init_cmd = "011") then		-- start checking busy flag
					delay_count <= (others => '0');
					init_cmd <= init_cmd + 1;
					db_out <= x"38";
					state <= en_h;
					next_state <= init;
				elsif (init_cmd = "100") then  -- DISP OFF
					delay_count <= (others => '0');
					init_cmd <= init_cmd + 1;
					db_out <= x"08";
					state <= en_h;
					next_state <= init;
				elsif (init_cmd = "101") then  -- DISP CLEAR (can take > 1s to execute)
					delay_count <= (others => '0');
					init_cmd <= init_cmd + 1;
					db_out <= x"01";
					state <= en_h;
					next_state <= init;
				elsif (init_cmd = "110") then   -- ENT_MODE_SET
					delay_count <= (others => '0');
					db_out <= x"06";
					state <= en_h;
					next_state <= disp_on; -- disp_on
				end if;
--================================================
-- commands
--================================================
			when disp_on =>
				delay_count <= (others => '0');
				rs <= '0';
				rw_reg <= '0';
				db_out <= x"0F";
				state <= en_h;
				next_state <= wr_ddram;
				
			when wr_ddram =>				-- unintended muxes instantiated?
				delay_count <= (others => '0');
				rs <= '1';
				rw_reg <= '0';
				count <= count + 1;
				if (count <= 16) then
					db_out <= line1(count);
					state <= en_h;
					next_state <= wr_ddram;
				else
					count <= 0;
					state <= home;
					next_state <= home;
				end if;	
				
			when clr_disp =>
				delay_count <= (others => '0');
				db_out <= x"01";  -- clr disp ~1.58ms, can take > 1s to execute
				rs <= '0';
				rw_reg <= '0';
				state <= en_h;
				next_state <= home;					
						
			when home =>
				delay_count <= (others => '0');					
				if (pb = '0') then
					state <= clr_disp;
					next_state <= home;
				elsif (pb = '1') then
					state <= home;
					next_state <= home;
				end if;
					
--================================================
-- enable controller
--================================================
			when en_h =>
				if delay_count < delay_500ns then  -- N = 25 (~500ns period) or (maybe 24)
					if (delay_count >= delay_40ns and delay_count <= delay_240ns) then	
						en <= '1';
						if delay_count = delay_240ns-1 and rw_reg = '1' then
							if db_in(7) = '0' then
								check_bf_f <= '1';	
							else 
								check_bf_f <= '0';
							end if;
						end if;
					end if;
				else
					delay_count <= (others => '0');
					if check_bf_f = '1' then
						check_bf_f <= '0';
						rw_reg <= '0';
						state <= next_state;
					else
						state <= chk_bf;
					end if;
				end if;
				
--================================================
-- check busy flag
--================================================
			when chk_bf =>
				delay_count <= (others => '0');
				rs <= '0';
				rw_reg <= '1';
				state <= en_h;
		end case;
	end if;
end process;
end arch;
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top