Timing problem with HD44780 LCD controller on FPGA using VHDL

Discussion in 'VHDL' started by BlackHelicopter, Feb 27, 2011.

  1. BlackHelicopter

    BlackHelicopter

    Joined:
    Jun 3, 2010
    Messages:
    14
    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 (Text):
    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;
     
    BlackHelicopter, Feb 27, 2011
    #1
    1. Advertisements

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. cehon
    Replies:
    1
    Views:
    2,470
    ALuPin@web.de
    Sep 15, 2005
  2. meshoshow
    Replies:
    3
    Views:
    5,690
    Mike Treseler
    Dec 15, 2006
  3. r_spaargaren@hotmail.com

    Program LCD HD44780 with 68HC11 in Handyboard

    r_spaargaren@hotmail.com, Oct 26, 2007, in forum: C Programming
    Replies:
    2
    Views:
    746
    Mark McIntyre
    Oct 27, 2007
  4. vx100miles
    Replies:
    1
    Views:
    1,966
    vx100miles
    Nov 21, 2008
  5. BlackHelicopter
    Replies:
    0
    Views:
    1,219
    BlackHelicopter
    Dec 9, 2010
Loading...

Share This Page