Forum Discussion
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
Honored 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:
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: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;
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:--======================= 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; --==================================================================--
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)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...........