Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

Problems HD44780 - LCD - ALTERA DE2-115...

Hey guys,

I am new in VHDL and tried to control the LCD, but no chance... It needs to be a simple error, but because I am new in FPGA/VHDL is going to be difficult for me to fix it.

I made a simulation with modelsim (all fine...), I checked the out- and input-pin-setting a thousand times (all fine...) and I checked the board (DE2-115) with the control panel (all works...)

I mixed up a code I found in the internet for an (working?) example and modified it a little bit.

General function: At first the program initialize the LCD and goes in a loop for writing letters to the lcd. Via 7 switchs the user is defining the binary code of the letters which should be written on the LCD.

Result: After transfering the code, the FPGA doesnt react to a chancing of the switchs. The standart message "Welcome to the Alterna DE2-115" is shown up, thats all... ;-(

I made some comments to understand the functions a little bit faster...

Hopefully someone can find the error... thx to all answers...

-------------------------------------------------------------------

-- ASCII HEX TABLE

-- Hex Low Hex Digit

-- Value 0 1 2 3 4 5 6 7 8 9 A B C D E F

------\---------------------------------------a-------------------------

--H 2 | SP ! " # $ % & ' ( ) * + , - . /

--i 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ?

--g 4 | @ A B C D E F G H I J K L M N O

--h 5 | P Q R S T U V W X Y Z [ \ ] ^ _

-- 6 | ` a b c d e f g h i j k l m n o

-- 7 | p q r s t u v w x y z { | } ~ DEL

-----------------------------------------------------------------------

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.all;

USE IEEE.STD_LOGIC_ARITH.all;

USE IEEE.STD_LOGIC_UNSIGNED.all;

entity lcd_control is

port

(

trigger,trigger2, clk : in std_logic;

ascii : in std_logic_vector(7 downto 0);

lcd_rs, lcd_e, lcd_rw : out std_logic;

lcd_data : out std_logic_vector(7 downto 0);

lcd_an : out std_logic

);

end lcd_control;

architecture behv of lcd_control is

type state_type is ( START, START_WAIT, FUNC_SET_WAIT, DISP_ON_WAIT,

DROP_E, HOLD,

FUNC_SET, DISP_ON, DISP_CLEAR, MODE_SET,

WAIT_CHAR, DISP_CLEAR_WAIT,

WAIT_TRIGGER_RESET,

CHK_CNT, LINE2, HOME);

signal state, next_command : state_type;

signal char_cnt : std_logic_vector(5 downto 0);

signal wait_cnt : std_logic_vector(7 downto 0);

begin

process(clk)

begin

if trigger2='1' then -- a switch to turn the lcd on and off

lcd_an<='1';

lcd_rw<='0'; -- setting the rw permenantly to 1

else

lcd_an<='0';

end if;

state <= START;

case state is

when START =>

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"38"; -- set the lcd to 8 bit lenght

wait_cnt<=X"00";

state <= DROP_E; -- function of DROP_E: just sets lcd_e to '1' and state goes to next_command

next_command <= START_WAIT;

when START_WAIT => -- waiting for a few msec

if wait_cnt < X"10" then

wait_cnt <= wait_cnt +1;

state <= START_WAIT;

else

state <= FUNC_SET;

wait_cnt <= X"00";

end if;

when FUNC_SET =>

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"38";

state <= DROP_E;

next_command <= FUNC_SET_WAIT;

when FUNC_SET_WAIT =>

if wait_cnt < X"10" then

wait_cnt <= wait_cnt +1;

state <= FUNC_SET_WAIT;

else

state <= DISP_ON;

wait_cnt <= X"00";

end if;

when DISP_ON =>

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"0F"; -- set the lcd to Display on, Cursor is displayed, Blinking enable,

state <= DROP_E;

next_command <= DISP_ON_WAIT;

when DISP_ON_WAIT =>

if wait_cnt < X"10" then

wait_cnt <= wait_cnt +1;

state <= DISP_ON_WAIT;

else

state <= DISP_CLEAR;

wait_cnt <= X"00";

end if;

when DISP_CLEAR =>

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"01"; -- command: clear the display

wait_cnt <= X"00";

state <= DROP_E;

next_command <= DISP_CLEAR_WAIT;

when DISP_CLEAR_WAIT =>

if wait_cnt < X"10" then

wait_cnt <= wait_cnt +1;

state <= DISP_CLEAR_WAIT;

else

state <= MODE_SET;

wait_cnt <= X"00";

end if;

when MODE_SET =>

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"06"; -- Cursor moves right, Display shift enabled.

state <= DROP_E;

next_command <= WAIT_CHAR;

---------------- initialization done, Loop of writing begins -------------------------------------------

-- WAIT_CHAR -> DROP_E -> HOLD -> WAIT_TRIGGER_RESET -> CHK_CNT -> LINE2 -> DROP_E -> HOLD -> |

-- | |

-- ^ -> HOME -> DROP_E -> HOLD -> |

-- | | |

-- | v v

-- |----------------------------------------<<-------------------------------------------|

-------------------------------------------------------------------------------------------------

when WAIT_CHAR =>

if trigger = '0' then -- trigger is set to a switch

lcd_e <= '1';

lcd_rs <= '1';

lcd_data <= ascii; -- ascii is defined through 7 switchs

char_cnt <= char_cnt +1; -- a counter for the written letters

state <= DROP_E;

next_command <= WAIT_TRIGGER_RESET;

else

next_command <= WAIT_CHAR;

end if;

when WAIT_TRIGGER_RESET => -- loop, waiting for an change at the switch

if trigger = '0' then

state <= WAIT_TRIGGER_RESET;

else

state <= CHK_CNT;

end if;

when CHK_CNT => -- checking if the first line is full of letters,

if char_cnt = X"10" then

state <= LINE2;

elsif char_cnt = X"20" then

state <= HOME; -- clears the display

else

state <= WAIT_CHAR;

end if;

when LINE2 => -- starts writing at the secound line

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"C0"; -- sets the DDRAM-Adress to '1000000'

state <= DROP_E;

next_command <= WAIT_CHAR;

when HOME =>

lcd_e <= '1';

lcd_rs <= '0';

lcd_data <= X"80"; -- sets the DDRAM-adress to '0000000'

char_cnt <= "000000";

state <= DROP_E;

next_command <= WAIT_CHAR;

when DROP_E =>

lcd_e <= '1';

state <= HOLD;

when HOLD =>

state <= next_command;

end case;

end process;

end behv;

1 Reply

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Obviously I'm reviving an old thread here.... so perhaps this will help out future readers.

    Regarding the code posted:

    I noticed that your Clock process.......... as shown below:

    process(clk)
    begin
    if trigger2='1' then -- a switch to turn the lcd on and off
    lcd_an<='1';
    lcd_rw<='0'; -- setting the rw permenantly to 1
    else
    lcd_an<='0';
    end if;

    You have the port "clk" declared within your entity:

    clk : in std_logic;

    However I don't see any process that uses the "clk" port at all.... anywhere within your code.

    A clock is needed for the FPGA to create the required timing signals.

    Usually you have a clock process similar to what is shown below, in order to generate the specific timing signals you need for the display you are using.

    The Altera DE2 uses the standard HD44780 LCD display, and it requires a 400Hz clock signal.

    Using the 50Mhz clock source on the DE2, Your process would look something like this:

    --======================= CLOCK SIGNALS ============================--  
    process(clock_50)
    begin
          if (rising_edge(clock_50)) then
             if (reset = '0') then
                clk_count_400hz <= x"00000";
                clk_400hz_enable <= '0';
             else
                if (clk_count_400hz <= x"0F424") then           
                       clk_count_400hz <= clk_count_400hz + 1;
                       clk_400hz_enable <= '0';
                else
                       clk_count_400hz <= x"00000";
                       clk_400hz_enable <= '1';
                end if;
             end if;
          end if;
    end process;  
    --==================================================================--

    The statement in the above code:

    "IF (clk_count_400hz <= x"0F424") THEN"

    This is just the HEX reset value for the counter that is needed when using a 50Mhz source. This creates your 400Hz signal that is needed.

    The Process for your State machine should begins with an IF THEN ELSIF statement to provide the appropriate 400Hz clocking

    to drive the State machine through its various states.

    Place the following code before your State machines "CASE state IS" statement.

    As shown below:

    process (clock_50, reset)
    begin
            if reset = '0' then
               state <= reset1;
               data_bus_value <= x"38"; -- RESET
               next_command <= reset2;
               lcd_e <= '1';
               lcd_rs <= '0';
               lcd_rw_int <= '0';  
        
        
        
            elsif rising_edge(clock_50) then
                 if clk_400hz_enable = '1' then  
                     
                 
                     case state is
                            |
                            |
                            \/
                   Proceed with your State machine Statements...........
    

    Now for those of you that are interested......

    I have recently made a detailed instructional video on how to drive the HD44780 using VHDL.

    I also Demo the code on an Altera DE2 board. So feel free to review this if need be.

    https://youtu.be/ciimbdyj7w4 (https://youtu.be/ciimbdyj7w4)

    Cheers!

    -Gerry

    http://www.digital-circuitry.com (http://www.digital-circuitry.com)