OpenCores
URL https://opencores.org/ocsvn/hd44780_driver/hd44780_driver/trunk

Subversion Repositories hd44780_driver

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /hd44780_driver/trunk
    from Rev 6 to Rev 5
    Reverse comparison

Rev 6 → Rev 5

/trunk/lcd_driver_hd44780.qpf
0,0 → 1,30
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2011 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 32-bit
# Version 11.1 Build 216 11/23/2011 Service Pack 1 SJ Web Edition
# Date created = 09:17:30 September 29, 2012
#
# -------------------------------------------------------------------------- #
 
QUARTUS_VERSION = "11.1"
DATE = "09:17:30 September 29, 2012"
 
# Revisions
 
PROJECT_REVISION = "lcd_driver_hd44780"
/trunk/lcd_driver_hd44780_module.vhd
0,0 → 1,500
-- Filename: lcd_driver_hd44780_module.vhd
-- Filetype: VHDL Source Code
-- Date: 26 oct 2012
-- Update: -
-- Description: VHDL Description for driving an HD44780 based LCD driver
-- Author: J. op den Brouw
-- State: Demo
-- Error: -
-- Version: 1.2alpha
-- Copyright: (c)2012, De Haagse Hogeschool
 
-- This file contains a VHDL description for driving an HD44780 based LCD
-- driver, see for a standard information of such a display:
-- https://decibel.ni.com/content/servlet/JiveServlet/download/2741-3-3217/hd44780.pdf
--
-- Currently, this driver uses the 8-bit databus mode. This is not a big problem
-- for most FPGA's because of the numerous pins.
--
-- Please note that there are a lot of almost-the-same displays available, so
-- it's not guaranteed to work with all displays available. Also, timing may differ.
--
-- This code is tested on a Terasic DE0-board with an optional
-- LCD display. See the weblinks
-- http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=364
-- http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=78&No=396
-- for more info. The display used has only two lines.
--
-- This VHDL description can both be simulated and synthesized.
--
-- This driver has a User Side and a LCD Side. The user is to interface at the User Side
-- and has a number of "routines" at her disposal. The User Side implements the following
-- inputs/routines in order of priority:
--
-- Command inputs:
-- init: a logic 1 initializes the display
-- cls: a logic 1 clears the display (and goes to home)
-- home: a logic 1 sets the cursor to row 0, column 0
-- goto10: a logic 1 sets the cursor to row 1, column 0
-- goto20: a logic 1 sets the cursor to row 2, column 0
-- goto30: a logic 1 sets the cursor to row 3, column 0
-- wr: a logic 1 writes a character to the display
--
-- Data inputs:
--
-- data: an 8-bit data to be written to the display
--
-- The user has one observable output:
--
-- busy: a logic 1 indicates that the driver is currently
-- busy driving the display, a logic 0 indicates that
-- the driver waits for the next command.
--
-- The user can supply the next generics, which are processed at
-- instantiation of the module:
--
-- freq: the clock frequency at which the hardware has to run.
-- this frequency is mandatory because of internal delays
-- calculated, defaults to 50 MHz.
-- areset_pol:
-- the polarity of the reset signal, defaults to High (1)
-- time_init1:
-- the time to wait after Vcc > 4.5 V
-- time_init2:
-- the time to wait after first "contact"
-- time_init3:
-- the time to wait after the second contact
-- time_tas:
-- the RW and RS signal setup time with respect to the positive
-- edge of the E pulse
-- time_cycle_e:
-- the complete cycle time
-- time_pweh:
-- the E pulse width high time
-- time_no_bf:
-- time to wait before command completion if no Busy Flag reading is done,
-- some designs connect RW to logic 0, so reading from the LCD is not
-- possible, saves a pin.
-- cursor_on:
+-- blink_on: +-- true to let the cursor blink, false for no blink (just a underscore) +-- use_bf: true if Busy Flag reading is to be used, false for no BF reading +-- +-- Note: it's not possible to write command codes to the display. +-- +-- Changes to v1.0: LCD_E is renamed to LCD_EN +-- LCD_DB is renamed to LCD_DATA +-- busy is now registered +-- removed hardware simulation architecture +-- +-- Changes to v1.1: added timing generics for better steering of the E pulse cycle +-- implemented cursor on/off/blink with generic parameters +-- +-- Changes to v1.2: added Busy Flag reading mode, selectable at instantiation time +-- LCD_EN changes back to LCD_E +-- LCD_DATA changed back to LCD_DB +-- +-- To do: use 4-bit mode or 8-bit mode at instantiation time +-- + +-- The libraries to use. +library ieee; +use ieee.std_logic_1164.all; + +-- The entity of the LCD Driver Module. +entity lcd_driver_hd44780_module is + generic (freq : integer := 50000000; + areset_pol : std_logic := '1'; + time_init1 : time := 40 ms; + time_init2 : time := 4100 us; + time_init3 : time := 100 us; + time_tas : time := 60 ns; + time_cycle_e : time := 1000 ns; + time_pweh : time := 500 ns; + time_no_bf : time := 2 ms; + cursor_on : boolean := false; + blink_on : boolean := false; + use_bf : boolean := true + ); + port (clk : in std_logic; + areset : in std_logic; + -- User site + init : in std_logic; + data : in std_logic_vector(7 downto 0); + wr : in std_logic; + cls : in std_logic; + home : in std_logic; + goto10 : in std_logic; + goto20 : in std_logic; + goto30 : in std_logic; + busy : out std_logic; + -- LCD side + LCD_E : out std_logic; + LCD_RS : out std_logic; + LCD_RW : out std_logic; + LCD_DB : inout std_logic_vector(7 downto 0) + ); +end entity lcd_driver_hd44780_module; + +-- This architecture drives the LCD. +architecture hardware_driver of lcd_driver_hd44780_module is + +-- Delays... Please note that if the frequency is (too) low, +-- some of the delays will 0. The code will take care of that. +-- Converting time to integer is problematic. Please note the use of +-- the simulator time step in the calculations. +-- The simulator timestep +constant simulator_timestep : time := 1 ns; +-- Number of simulator timesteps per second. +constant sim_steps_per_sec : real := real(1 sec/simulator_timestep); + +constant delay_init1 : integer := integer( real(freq) * real(time_init1/simulator_timestep) / sim_steps_per_sec); +constant delay_init2 : integer := integer( real(freq) * real(time_init2/simulator_timestep) / sim_steps_per_sec); +constant delay_init3 : integer := integer( real(freq) * real(time_init3/simulator_timestep) / sim_steps_per_sec); +constant delay_tas : integer := integer( real(freq) * real(time_tas/simulator_timestep) / sim_steps_per_sec); +constant delay_cycle_e : integer := integer( real(freq) * real(time_cycle_e/simulator_timestep) / sim_steps_per_sec); +constant delay_pweh : integer := integer( real(freq) * real(time_pweh/simulator_timestep) / sim_steps_per_sec); +constant delay_no_bf : integer := integer( real(freq) * real(time_no_bf/simulator_timestep) / sim_steps_per_sec); + +-- The next statements do work in Quartus but not in (32 bit) ModelSim... +--constant delay_init1 : integer := integer(real(freq)*real(time'pos(time_init1)) / real(time'pos(1 sec))); +--constant delay_init2 : integer := integer(real(freq)*real(time'pos(time_init2)) / real(time'pos(1 sec))); +--constant delay_init3 : integer := integer(real(freq)*real(time'pos(time_init3)) / real(time'pos(1 sec))); +--constant delay_tas : integer := integer(real(freq)*real(time'pos(time_tas)) / real(time'pos(1 sec))); +--constant delay_cycle_e : integer := integer(real(freq)*real(time'pos(time_cycle_e)) / real(time'pos(1 sec))); +--constant delay_pweh : integer := integer(real(freq)*real(time'pos(time_pweh)) / real(time'pos(1 sec))); +--constant delay_no_bf : integer := integer(real(freq)*real(time'pos(time_no_bf)) / real(time'pos(1 sec))); + +-- Time the E signal must be low following E high +constant delay_pwel : integer := delay_cycle_e-delay_pweh; + +-- Counter for the delays. Timer would be a better choice. +-- Range should be to the longest delay. +signal delay_counter : integer range 0 to delay_init1; + +-- Should we use Busy Flag reading? +signal use_bf_int : std_logic; + +-- The states of the state machine. +type state_type is (reset, command_init, command_init_1, command_init_2, command_init_3, + command_init_4, command_init_5, command_init_6, command_init_7, command_init_8, + command_init_9, command_init_10, command_init_11, command_init12, + wait_for_command, + command_cls, command_home, + command_goto10, command_goto20, command_goto30, command_wr, + pulse_e, pulse_e_1, pulse_e_2, pulse_e_3, pulse_e_4, + pulse_busy_flag, pulse_busy_flag_1, pulse_busy_flag_2, pulse_busy_flag_3, + pulse_busy_flag_4, pulse_busy_flag_5); + + +-- The current state and one for the return state (to facilitate return to the caller). +signal current_state, return_state : state_type; +begin + + -- The state machine ;-) + nsl_state: process (clk, areset) is + -- Function to translate a boolean to std_logic + function bool_to_stdlogic(l: boolean) return std_logic is + begin + if l then + return('1'); + else + return('0'); + end if; + end function bool_to_stdlogic; + begin + if (areset = '1' and areset_pol = '1') or (areset = '0' and areset_pol = '0') then + current_state <= reset; + delay_counter <= 0; + busy <= '1'; + LCD_DB <= (others => 'Z'); + LCD_E <= '0'; + LCD_RS <= '0'; + LCD_RW <= '0'; + use_bf_int <= '0'; + elsif rising_edge(clk) then + -- Default is busy + busy <= '1'; + -- Default values of the LCD side + LCD_E <= '0'; + LCD_RW <= '0'; + case current_state is + when reset|command_init => + -- The logic is reset. Start initialization routine. + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + use_bf_int <= '0'; + delay_counter <= delay_init1; + current_state <= command_init_1; + when command_init_1 => + -- Wait until Vcc > 4.5 V... + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + use_bf_int <= '0'; + -- If done write 0x30 to the LCD + if delay_counter = 0 or delay_counter = 1 then + LCD_DB <= "00110000"; -- 0x30 + current_state <= pulse_e; + return_state <= command_init_2; + else + delay_counter <= delay_counter-1; + end if; + when command_init_2 => + -- Next, set up wait for 4.1 ms + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + use_bf_int <= '0'; + delay_counter <= delay_init2; + current_state <= command_init_3; + when command_init_3 => + -- Wait... + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + use_bf_int <= '0'; + -- If done write 0x30 to the LCD + if delay_counter = 0 or delay_counter = 1 then + LCD_DB <= "00110000"; -- 0x30 + current_state <= pulse_e; + return_state <= command_init_4; + else + delay_counter <= delay_counter-1; + end if; + when command_init_4 => + -- Next, set up wait for 100 us + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + use_bf_int <= '0'; + delay_counter <= delay_init3; + current_state <= command_init_5; + when command_init_5 => + -- Wait... + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + use_bf_int <= '0'; + -- If done write 0x30 to the LCD + if delay_counter = 0 or delay_counter = 1 then + LCD_DB <= "00110000"; -- 0x30 + current_state <= pulse_e; + return_state <= command_init_6; + else + delay_counter <= delay_counter-1; + end if; + when command_init_6 => + -- Power up is now done, so let's enter some reasonable values... + LCD_DB <= "00110000"; + LCD_RS <= '0'; + use_bf_int <= bool_to_stdlogic(use_bf); + current_state <= pulse_e; + return_state <= command_init_7; + when command_init_7 => + -- 8-bit bus, 2(?) lines, 5x7 characters + LCD_DB <= "00111100"; -- 0x3C + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= command_init_8; + when command_init_8 => + -- Display off + LCD_DB <= "00001000"; -- 0x08 + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= command_init_9; + when command_init_9 => + -- Display clear + LCD_DB <= "00000001"; -- 0x01 + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= command_init_10; + when command_init_10 => + -- Display on, cursor and blink... + LCD_DB <= "000011" & bool_to_stdlogic(cursor_on) & bool_to_stdlogic(blink_on); -- 0x0C + ... + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= command_init_11; + when command_init_11 => + -- Mode set, increment cursor address, cursor shift + LCD_DB <= "00000110"; -- 0x06 + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= wait_for_command; + + -- The command dispatcher! This state waits for one of + -- the command inputs to be logic '1' and 'starts' the + -- accompanying routine. Note the priority encoding! + when wait_for_command => + LCD_DB <= (others => 'Z'); + LCD_RS <= '0'; + busy <= '0'; + if init = '1' then + busy <= '1'; + current_state <= command_init; + elsif cls = '1' then + busy <= '1'; + current_state <= command_cls; + elsif home = '1' then + busy <= '1'; + current_state <= command_home; + elsif goto10 = '1' then + busy <= '1'; + current_state <= command_goto10; + elsif goto20 = '1' then + busy <= '1'; + current_state <= command_goto20; + elsif goto30 = '1' then + busy <= '1'; + current_state <= command_goto30; + elsif wr = '1' then + -- Read in data! Do NOT forget that here! + LCD_DB <= data; + busy <= '1'; + current_state <= command_wr; + end if; + + when command_cls => + -- Display clear + LCD_DB <= "00000001"; + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= wait_for_command; + + when command_home => + -- Cursor home + LCD_DB <= "00000010"; + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= wait_for_command; + + when command_goto10 => + -- Cursor to beginning of line 2nd line... + LCD_DB <= "11000000"; --0x80+0x40; + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= wait_for_command; + + when command_goto20 => + -- Cursor to beginning of line 3rd line... + LCD_DB <= "10010000"; --0x80+0x10; + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= wait_for_command; + + when command_goto30 => + -- Cursor to beginning of line 4th line... + LCD_DB <= "11010000"; --0x80+0x50; + LCD_RS <= '0'; + current_state <= pulse_e; + return_state <= wait_for_command; + + when command_wr => + -- Start character write cycle + -- Do NOT set data here! + LCD_RS <= '1'; + current_state <= pulse_e; + return_state <= wait_for_command; + + -- -- + -- Provide E strobing for data transfer. + -- Writes data byte to the LCD. + -- Please note, DATA and RS are set by the caller! + when pulse_e => + -- wait 60 ns before E -> 1 (tAS) + delay_counter <= delay_tas; + current_state <= pulse_e_1; + when pulse_e_1 => + if delay_counter = 0 or delay_counter = 1 then + -- timer set: E = 1 for 500 ns (PWeh) + delay_counter <= delay_pweh; + current_state <= pulse_e_2; + else + delay_counter <= delay_counter-1; + end if; + when pulse_e_2 => + LCD_E <= '1'; + if delay_counter = 0 or delay_counter = 1 then + -- timer set: E = 0 for 500 ns (tCycleE-PWeh) + delay_counter <= delay_pwel; + current_state <= pulse_e_3; + else + delay_counter <= delay_counter-1; + end if; + when pulse_e_3 => + LCD_E <= '0'; + -- Command completion, check for use busy flag + if delay_counter = 0 or delay_counter = 1 then + -- If no busy flag used, wait for a amount of time. + if use_bf_int = '0' then + delay_counter <= delay_no_bf; + current_state <= pulse_e_4; + else -- BF used + current_state <= pulse_busy_flag; + end if; + else + delay_counter <= delay_counter-1; + end if; + when pulse_e_4 => + -- Wait for the delay to finsh and then return to the caller. + if delay_counter = 0 or delay_counter = 1 then + current_state <= return_state; + else + delay_counter <= delay_counter-1; + end if; + + -- Let's read the busy flag, see if the module is busy... + when pulse_busy_flag => + LCD_DB <= (others => 'Z'); + LCD_RW <= '1'; + LCD_RS <= '0'; + -- wait 60 ns before E -> 1 (tAS) + delay_counter <= delay_tas; + current_state <= pulse_busy_flag_1; + when pulse_busy_flag_1 => + LCD_RW <= '1'; + if delay_counter = 0 or delay_counter = 1 then + -- timer set: E = 1 for 500 ns (tPWeh) + delay_counter <= delay_pweh; + current_state <= pulse_busy_flag_2; + else + delay_counter <= delay_counter-1; + end if; + when pulse_busy_flag_2 => + LCD_E <= '1'; + LCD_RW <= '1'; + if delay_counter = 0 or delay_counter = 1 then + -- timer set: E = 0 for 500 ns (tPWel) + delay_counter <= delay_pwel; + current_state <= pulse_busy_flag_3; + else + delay_counter <= delay_counter-1; + end if; + when pulse_busy_flag_3 => + LCD_E <= '0'; + LCD_RW <= '1'; + if LCD_DB(7) = '0' then + -- operation ended + current_state <= pulse_busy_flag_4; + else + -- operation in progress + current_state <= pulse_busy_flag_5; + end if; + when pulse_busy_flag_4 => + if delay_counter = 0 or delay_counter = 1 then + -- Operation ended, return caller + current_state <= return_state; + else + delay_counter <= delay_counter-1; + end if; + when pulse_busy_flag_5 => + if delay_counter = 0 or delay_counter = 1 then + -- Operation in progress, read BF again + current_state <= pulse_busy_flag; + else + delay_counter <= delay_counter-1; + end if; + + when others => null; + end case; + end if; + + end process; + +end architecture hardware_driver;
/trunk/example_driver.vhd
0,0 → 1,277
-- Filename: example_driver.vhd
-- Filetype: VHDL Source Code
-- Date: 26 oct 2012
-- Update: -
-- Description: VHDL Description of example driver
-- Author: J. op den Brouw
-- State: Demo
-- Error: -
-- Version: 1.1alpha
-- Copyright: (c)2012, De Haagse Hogeschool
 
-- This VHDL code is a example description on how to use the
-- HD44780 LCD display driver module. It writes 4x16 characters
-- to the display, presuming that the display has four lines.
--
-- This code is tested on a Terasic DE0-board with an optional
-- LCD display. See the weblinks
-- http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=364
-- http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=78&No=396
-- for more info. The display used has only two lines.
 
-- After a line has written completely, the cursor is moved to
-- the beginning of the next line. After the last line is written,
-- this code goes into hold mode.
--
 
-- Libraries et al.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
-- The entity of a Terasic DE0-board.
entity example_driver is
port (CLOCK_50 : in std_logic;
BUTTON : in std_logic_vector(2 downto 0);
SW : in std_logic_vector(9 downto 0);
LEDG : out std_logic_vector(9 downto 0);
HEX3_D : out std_logic_vector(6 downto 0);
HEX2_D : out std_logic_vector(6 downto 0);
HEX1_D : out std_logic_vector(6 downto 0);
HEX0_D : out std_logic_vector(6 downto 0);
HEX0_DP : out std_logic;
HEX1_DP : out std_logic;
HEX2_DP : out std_logic;
HEX3_DP : out std_logic;
-- LCD of the DE0 board
LCD_EN : out std_logic;
LCD_RS : out std_logic;
LCD_RW : out std_logic;
LCD_DATA : inout std_logic_vector(7 downto 0);
LCD_BLON : out std_logic
);
end entity example_driver;
 
-- The architecture!
architecture hardware of example_driver is
-- Component declaration of the LCD module
component lcd_driver_hd44780_module is
generic (freq : integer := 50000000;
areset_pol : std_logic := '1';
time_init1 : time := 40 ms;
time_init2 : time := 4100 us;
time_init3 : time := 100 us;
time_tas : time := 60 ns;
time_cycle_e : time := 1000 ns;
time_pweh : time := 500 ns;
time_no_bf : time := 2 ms;
cursor_on : boolean := false;
blink_on : boolean := false;
use_bf : boolean := true
);
port (clk : in std_logic;
areset : in std_logic;
-- User site
init : in std_logic;
data : in std_logic_vector(7 downto 0);
wr : in std_logic;
cls : in std_logic;
home : in std_logic;
goto10 : in std_logic;
goto20 : in std_logic;
goto30 : in std_logic;
busy : out std_logic;
-- LCD side
LCD_E : out std_logic;
LCD_RS : out std_logic;
LCD_RW : out std_logic;
LCD_DB : inout std_logic_vector(7 downto 0)
);
end component lcd_driver_hd44780_module;
 
-- The system's frequency
constant sys_freq : integer := 50000000;
 
signal areset : std_logic;
signal clk : std_logic;
signal init : std_logic;
signal data : std_logic_vector(7 downto 0);
signal wr : std_logic;
signal cls : std_logic;
signal home : std_logic;
signal goto10 : std_logic;
signal goto20 : std_logic;
signal goto30 : std_logic;
signal busy : std_logic;
 
type state_type is (reset, write_char, write_char_wait, update, update_linecount,
update_linecount_wait, write_char_1, write_char_1_wait,
write_char_2, write_char_2_wait, write_char_3, write_char_4, hold,
hold2);
signal state : state_type;
 
-- A string of 16 characters
subtype string16_type is string(1 to 16);
-- An array of 4 strings of 16 characters.
type message4x16_type is array (1 to 4) of string16_type;
 
-- The four-line message
constant message : message4x16_type :=
( 1 => "1Elektrotechniek",
2 => "2 LCD HD44780 ",
3 => "3Driver in VHDL!",
4 => "4J. op den Brouw");
 
-- Counts the characters on a line.
signal character_counter : integer range 1 to 16;
-- Counts the lines.
signal line_counter : integer range 1 to 4;
 
begin
 
-- Push buttons are active low.
areset <= not BUTTON(0);
 
-- The clock
clk <= CLOCK_50;
-- Use LCD module.
lcdm : lcd_driver_hd44780_module
generic map (freq => sys_freq, areset_pol => '1', time_cycle_e => 2000 ns, time_pweh => 500 ns,
cursor_on => false, blink_on => false, use_bf => false)
port map (clk => clk, areset => areset, init => init, data => data, wr => wr, cls => cls,
home => home, goto10 => goto10, goto20 => goto20, goto30 => goto30, busy => busy,
LCD_E => LCD_EN, LCD_RS => LCD_RS, LCD_RW => LCD_RW, LCD_DB => LCD_DATA);
-- The client side
drive: process (clk, areset) is
variable aline : string16_type;
begin
if areset = '1' then
wr <= '0';
init <= '0';
cls <= '0';
home <= '0';
goto10 <= '0';
goto20 <= '0';
goto30 <= '0';
LEDG(0) <= '0';
data <= "00000000";
character_counter <= 1;
state <= reset;
elsif rising_edge(clk) then
wr <= '0';
init <= '0';
cls <= '0';
home <= '0';
goto10 <= '0';
goto20 <= '0';
goto30 <= '0';
LEDG(0) <= '0';
data <= "00000000";
case state is
 
when reset =>
-- Wait for the LCD module ready
if busy = '0' then
state <= write_char;
end if;
-- Setup message counter, start at 1.
character_counter <= 1;
line_counter <= 1;
when write_char =>
LEDG(0) <= '1';
-- Set up WRITE!
-- Use the data from the string
aline := message(line_counter);
data <= std_logic_vector( to_unsigned( character'pos(aline(character_counter)),8));
wr <= '1';
state <= write_char_wait;
 
when write_char_wait =>
-- This state is needed so that the LCD driver
-- can process the write command. Note that data
-- and wr are registered outputs and get their
-- respective values while in *this* state. If you don't
-- want this behaviour, please make your outputs
-- non-registered.
state <= update;
when update =>
LEDG(0) <= '1';
-- Wait for the write complete
if busy = '0' then
-- If end of string, goto hold mode...
if line_counter = 4 and character_counter = 16 then
state <= hold;
-- If end of line...
elsif character_counter = 16 then
case line_counter is
when 1 => goto10 <= '1';
when 2 => goto20 <= '1';
when 3 => goto30 <= '1';
-- Never reached, but nice anyway...
when 4 => home <= '1';
when others => null;
end case;
-- Set new values of the counters
line_counter <= line_counter+1;
character_counter <= 1;
-- Goto the update state
state <= update_linecount;
else
-- Not the end of a lines, update the character counter.
character_counter <= character_counter+1;
state <= write_char;
end if;
end if;
when update_linecount =>
-- This state is needed so that the LCD driver
-- can process the gotoXX command. Note that the gotoXX
-- signals are registered outputs and get their
-- respective values while in *this* state. If you don't
-- want this behaviour, please make your outputs
-- non-registered.
state <= update_linecount_wait;
when update_linecount_wait =>
-- Wait for the LCD module ready
if busy = '0' then
state <= write_char;
end if;
-- The "hohouwer"
when hold =>
--state <= hold;
state <= hold2;
home <= '1';
when hold2 =>
state <= reset;
when others =>
null;
 
end case;
end if;
end process;
-- The unused outputs...
HEX3_D <= (others => '1');
HEX2_D <= (others => '1');
HEX1_D <= (others => '1');
HEX0_D <= (others => '1');
HEX3_DP <= '1';
HEX2_DP <= '1';
HEX1_DP <= '1';
HEX0_DP <= '1';
LEDG(9 downto 1) <= (others => '0');
-- Sadly, the LCD doesn't have a backlight...
LCD_BLON <= '0';
 
end architecture hardware;
/trunk/lcd_driver_hd44780.qsf
0,0 → 1,319
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2011 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 32-bit
# Version 11.1 Build 216 11/23/2011 Service Pack 1 SJ Web Edition
# Date created = 09:17:30 September 29, 2012
#
# -------------------------------------------------------------------------- #
#
# Notes:
#
# 1) The default values for assignments are stored in the file:
# lcd_driver_hd44780_assignment_defaults.qdf
# If this file doesn't exist, see file:
# assignment_defaults.qdf
#
# 2) Altera recommends that you do not modify this file. This
# file is updated automatically by the Quartus II software
# and any changes you make may be lost or overwritten.
#
# -------------------------------------------------------------------------- #
 
 
set_global_assignment -name FAMILY "Cyclone III"
set_global_assignment -name DEVICE EP3C16F484C6
set_global_assignment -name TOP_LEVEL_ENTITY example_driver
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "11.1 SP1"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "09:17:30 SEPTEMBER 29, 2012"
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
set_location_assignment PIN_D13 -to HEX0_DP
set_location_assignment PIN_B15 -to HEX1_DP
set_location_assignment PIN_A18 -to HEX2_DP
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484
set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 6
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name RESERVE_ALL_UNUSED_PINS_WEAK_PULLUP "AS INPUT TRI-STATED"
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
set_global_assignment -name SMART_RECOMPILE ON
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (VHDL)"
set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation
set_global_assignment -name VHDL_INPUT_VERSION VHDL_2008
set_global_assignment -name VHDL_SHOW_LMF_MAPPING_MESSAGES OFF
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_global_assignment -name EDA_TEST_BENCH_ENABLE_STATUS COMMAND_MACRO_MODE -section_id eda_simulation
set_global_assignment -name EDA_SIMULATION_RUN_SCRIPT tb_example_driver.do -section_id eda_simulation
set_location_assignment PIN_G21 -to CLOCK_50
set_location_assignment PIN_B12 -to CLOCK_50_2
set_location_assignment PIN_G8 -to DRAM_CAS_N
set_location_assignment PIN_G7 -to DRAM_CS_N
set_location_assignment PIN_E5 -to DRAM_CLK
set_location_assignment PIN_E6 -to DRAM_CKE
set_location_assignment PIN_B5 -to DRAM_BA_0
set_location_assignment PIN_A4 -to DRAM_BA_1
set_location_assignment PIN_F10 -to DRAM_DQ[15]
set_location_assignment PIN_E10 -to DRAM_DQ[14]
set_location_assignment PIN_A10 -to DRAM_DQ[13]
set_location_assignment PIN_B10 -to DRAM_DQ[12]
set_location_assignment PIN_C10 -to DRAM_DQ[11]
set_location_assignment PIN_A9 -to DRAM_DQ[10]
set_location_assignment PIN_B9 -to DRAM_DQ[9]
set_location_assignment PIN_A8 -to DRAM_DQ[8]
set_location_assignment PIN_F8 -to DRAM_DQ[7]
set_location_assignment PIN_H9 -to DRAM_DQ[6]
set_location_assignment PIN_G9 -to DRAM_DQ[5]
set_location_assignment PIN_F9 -to DRAM_DQ[4]
set_location_assignment PIN_E9 -to DRAM_DQ[3]
set_location_assignment PIN_H10 -to DRAM_DQ[2]
set_location_assignment PIN_G10 -to DRAM_DQ[1]
set_location_assignment PIN_D10 -to DRAM_DQ[0]
set_location_assignment PIN_E7 -to DRAM_LDQM
set_location_assignment PIN_B8 -to DRAM_UDQM
set_location_assignment PIN_F7 -to DRAM_RAS_N
set_location_assignment PIN_D6 -to DRAM_WE_N
set_location_assignment PIN_C8 -to DRAM_ADDR[12]
set_location_assignment PIN_A7 -to DRAM_ADDR[11]
set_location_assignment PIN_B4 -to DRAM_ADDR[10]
set_location_assignment PIN_B7 -to DRAM_ADDR[9]
set_location_assignment PIN_C7 -to DRAM_ADDR[8]
set_location_assignment PIN_A6 -to DRAM_ADDR[7]
set_location_assignment PIN_B6 -to DRAM_ADDR[6]
set_location_assignment PIN_C6 -to DRAM_ADDR[5]
set_location_assignment PIN_A5 -to DRAM_ADDR[4]
set_location_assignment PIN_C3 -to DRAM_ADDR[3]
set_location_assignment PIN_B3 -to DRAM_ADDR[2]
set_location_assignment PIN_A3 -to DRAM_ADDR[1]
set_location_assignment PIN_C4 -to DRAM_ADDR[0]
set_location_assignment PIN_R2 -to FL_ADDR[21]
set_location_assignment PIN_P3 -to FL_ADDR[20]
set_location_assignment PIN_P1 -to FL_ADDR[19]
set_location_assignment PIN_M6 -to FL_ADDR[18]
set_location_assignment PIN_M5 -to FL_ADDR[17]
set_location_assignment PIN_AA2 -to FL_ADDR[16]
set_location_assignment PIN_L6 -to FL_ADDR[15]
set_location_assignment PIN_L7 -to FL_ADDR[14]
set_location_assignment PIN_M1 -to FL_ADDR[13]
set_location_assignment PIN_M2 -to FL_ADDR[12]
set_location_assignment PIN_M3 -to FL_ADDR[11]
set_location_assignment PIN_N1 -to FL_ADDR[10]
set_location_assignment PIN_N2 -to FL_ADDR[9]
set_location_assignment PIN_P2 -to FL_ADDR[8]
set_location_assignment PIN_M4 -to FL_ADDR[7]
set_location_assignment PIN_M8 -to FL_ADDR[6]
set_location_assignment PIN_N6 -to FL_ADDR[5]
set_location_assignment PIN_N5 -to FL_ADDR[4]
set_location_assignment PIN_N7 -to FL_ADDR[3]
set_location_assignment PIN_P6 -to FL_ADDR[2]
set_location_assignment PIN_P5 -to FL_ADDR[1]
set_location_assignment PIN_P7 -to FL_ADDR[0]
set_location_assignment PIN_AA1 -to FL_BYTE_N
set_location_assignment PIN_N8 -to FL_CE_N
set_location_assignment PIN_R7 -to FL_DQ[0]
set_location_assignment PIN_P8 -to FL_DQ[1]
set_location_assignment PIN_R8 -to FL_DQ[2]
set_location_assignment PIN_U1 -to FL_DQ[3]
set_location_assignment PIN_V2 -to FL_DQ[4]
set_location_assignment PIN_V3 -to FL_DQ[5]
set_location_assignment PIN_W1 -to FL_DQ[6]
set_location_assignment PIN_Y1 -to FL_DQ[7]
set_location_assignment PIN_T5 -to FL_DQ[8]
set_location_assignment PIN_T7 -to FL_DQ[9]
set_location_assignment PIN_T4 -to FL_DQ[10]
set_location_assignment PIN_U2 -to FL_DQ[11]
set_location_assignment PIN_V1 -to FL_DQ[12]
set_location_assignment PIN_V4 -to FL_DQ[13]
set_location_assignment PIN_W2 -to FL_DQ[14]
set_location_assignment PIN_R6 -to FL_OE_N
set_location_assignment PIN_R1 -to FL_RST_N
set_location_assignment PIN_M7 -to FL_RY
set_location_assignment PIN_P4 -to FL_WE_N
set_location_assignment PIN_T3 -to FL_WP_N
set_location_assignment PIN_Y2 -to FL_DQ15_AM1
set_location_assignment PIN_J1 -to LEDG[0]
set_location_assignment PIN_J2 -to LEDG[1]
set_location_assignment PIN_J3 -to LEDG[2]
set_location_assignment PIN_H1 -to LEDG[3]
set_location_assignment PIN_F2 -to LEDG[4]
set_location_assignment PIN_E1 -to LEDG[5]
set_location_assignment PIN_C1 -to LEDG[6]
set_location_assignment PIN_C2 -to LEDG[7]
set_location_assignment PIN_B2 -to LEDG[8]
set_location_assignment PIN_B1 -to LEDG[9]
set_location_assignment PIN_F21 -to LCD_BLON
set_location_assignment PIN_F22 -to LCD_RS
set_location_assignment PIN_E22 -to LCD_RW
set_location_assignment PIN_E21 -to LCD_EN
set_location_assignment PIN_P22 -to PS2_KBCLK
set_location_assignment PIN_P21 -to PS2_KBDAT
set_location_assignment PIN_R21 -to PS2_MSCLK
set_location_assignment PIN_R22 -to PS2_MSDAT
set_location_assignment PIN_H2 -to BUTTON[0]
set_location_assignment PIN_G3 -to BUTTON[1]
set_location_assignment PIN_F1 -to BUTTON[2]
set_location_assignment PIN_Y21 -to SD_CLK
set_location_assignment PIN_Y22 -to SD_CMD
set_location_assignment PIN_AA22 -to SD_DAT0
set_location_assignment PIN_W21 -to SD_DAT3
set_location_assignment PIN_W20 -to SD_WP_N
set_location_assignment PIN_E11 -to HEX0_D[0]
set_location_assignment PIN_F11 -to HEX0_D[1]
set_location_assignment PIN_H12 -to HEX0_D[2]
set_location_assignment PIN_H13 -to HEX0_D[3]
set_location_assignment PIN_G12 -to HEX0_D[4]
set_location_assignment PIN_F12 -to HEX0_D[5]
set_location_assignment PIN_F13 -to HEX0_D[6]
set_location_assignment PIN_A13 -to HEX1_D[0]
set_location_assignment PIN_B13 -to HEX1_D[1]
set_location_assignment PIN_C13 -to HEX1_D[2]
set_location_assignment PIN_A14 -to HEX1_D[3]
set_location_assignment PIN_B14 -to HEX1_D[4]
set_location_assignment PIN_E14 -to HEX1_D[5]
set_location_assignment PIN_A15 -to HEX1_D[6]
set_location_assignment PIN_D15 -to HEX2_D[0]
set_location_assignment PIN_A16 -to HEX2_D[1]
set_location_assignment PIN_B16 -to HEX2_D[2]
set_location_assignment PIN_E15 -to HEX2_D[3]
set_location_assignment PIN_A17 -to HEX2_D[4]
set_location_assignment PIN_B17 -to HEX2_D[5]
set_location_assignment PIN_F14 -to HEX2_D[6]
set_location_assignment PIN_B18 -to HEX3_D[0]
set_location_assignment PIN_F15 -to HEX3_D[1]
set_location_assignment PIN_A19 -to HEX3_D[2]
set_location_assignment PIN_B19 -to HEX3_D[3]
set_location_assignment PIN_C19 -to HEX3_D[4]
set_location_assignment PIN_D19 -to HEX3_D[5]
set_location_assignment PIN_G15 -to HEX3_D[6]
set_location_assignment PIN_G16 -to HEX3_DP
set_location_assignment PIN_J6 -to SW[0]
set_location_assignment PIN_H5 -to SW[1]
set_location_assignment PIN_H6 -to SW[2]
set_location_assignment PIN_G4 -to SW[3]
set_location_assignment PIN_G5 -to SW[4]
set_location_assignment PIN_J7 -to SW[5]
set_location_assignment PIN_H7 -to SW[6]
set_location_assignment PIN_E3 -to SW[7]
set_location_assignment PIN_E4 -to SW[8]
set_location_assignment PIN_D2 -to SW[9]
set_location_assignment PIN_L22 -to VGA_VS
set_location_assignment PIN_L21 -to VGA_HS
set_location_assignment PIN_K22 -to VGA_B[0]
set_location_assignment PIN_K21 -to VGA_B[1]
set_location_assignment PIN_J22 -to VGA_B[2]
set_location_assignment PIN_K18 -to VGA_B[3]
set_location_assignment PIN_H22 -to VGA_G[0]
set_location_assignment PIN_J17 -to VGA_G[1]
set_location_assignment PIN_K17 -to VGA_G[2]
set_location_assignment PIN_J21 -to VGA_G[3]
set_location_assignment PIN_H19 -to VGA_R[0]
set_location_assignment PIN_H17 -to VGA_R[1]
set_location_assignment PIN_H20 -to VGA_R[2]
set_location_assignment PIN_H21 -to VGA_R[3]
set_location_assignment PIN_U22 -to UART_RXD
set_location_assignment PIN_U21 -to UART_TXD
set_location_assignment PIN_V21 -to UART_CTS
set_location_assignment PIN_V22 -to UART_RTS
set_location_assignment PIN_AB16 -to GPIO0_D[0]
set_location_assignment PIN_AA16 -to GPIO0_D[1]
set_location_assignment PIN_AA15 -to GPIO0_D[2]
set_location_assignment PIN_AB15 -to GPIO0_D[3]
set_location_assignment PIN_AA14 -to GPIO0_D[4]
set_location_assignment PIN_AB14 -to GPIO0_D[5]
set_location_assignment PIN_AB13 -to GPIO0_D[6]
set_location_assignment PIN_AA13 -to GPIO0_D[7]
set_location_assignment PIN_AB10 -to GPIO0_D[8]
set_location_assignment PIN_AA10 -to GPIO0_D[9]
set_location_assignment PIN_AB8 -to GPIO0_D[10]
set_location_assignment PIN_AA8 -to GPIO0_D[11]
set_location_assignment PIN_AB5 -to GPIO0_D[12]
set_location_assignment PIN_AA5 -to GPIO0_D[13]
set_location_assignment PIN_AB4 -to GPIO0_D[14]
set_location_assignment PIN_AA4 -to GPIO0_D[15]
set_location_assignment PIN_V14 -to GPIO0_D[16]
set_location_assignment PIN_U14 -to GPIO0_D[17]
set_location_assignment PIN_Y13 -to GPIO0_D[18]
set_location_assignment PIN_W13 -to GPIO0_D[19]
set_location_assignment PIN_U13 -to GPIO0_D[20]
set_location_assignment PIN_V12 -to GPIO0_D[21]
set_location_assignment PIN_R10 -to GPIO0_D[22]
set_location_assignment PIN_V11 -to GPIO0_D[23]
set_location_assignment PIN_Y10 -to GPIO0_D[24]
set_location_assignment PIN_W10 -to GPIO0_D[25]
set_location_assignment PIN_T8 -to GPIO0_D[26]
set_location_assignment PIN_V8 -to GPIO0_D[27]
set_location_assignment PIN_W7 -to GPIO0_D[28]
set_location_assignment PIN_W6 -to GPIO0_D[29]
set_location_assignment PIN_V5 -to GPIO0_D[30]
set_location_assignment PIN_U7 -to GPIO0_D[31]
set_location_assignment PIN_AB12 -to GPIO0_CLKIN[0]
set_location_assignment PIN_AA12 -to GPIO0_CLKIN[1]
set_location_assignment PIN_AB3 -to GPIO0_CLKOUT[0]
set_location_assignment PIN_AA3 -to GPIO0_CLKOUT[1]
set_location_assignment PIN_D22 -to LCD_DATA[0]
set_location_assignment PIN_D21 -to LCD_DATA[1]
set_location_assignment PIN_C22 -to LCD_DATA[2]
set_location_assignment PIN_C21 -to LCD_DATA[3]
set_location_assignment PIN_B22 -to LCD_DATA[4]
set_location_assignment PIN_B21 -to LCD_DATA[5]
set_location_assignment PIN_D20 -to LCD_DATA[6]
set_location_assignment PIN_C20 -to LCD_DATA[7]
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON
set_global_assignment -name OPTIMIZE_POWER_DURING_SYNTHESIS OFF
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name OPTIMIZE_POWER_DURING_FITTING OFF
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS OFF
set_global_assignment -name TIMEQUEST_REPORT_SCRIPT_INCLUDE_DEFAULT_ANALYSIS OFF
set_global_assignment -name TIMEQUEST_DO_CCPP_REMOVAL ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_MAP_LOGIC_TO_MEMORY_FOR_AREA OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT NORMAL
set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE BALANCED
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
 
 
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_instance_assignment -name SLEW_RATE 1 -to LCD_EN
set_instance_assignment -name SLEW_RATE 1 -to LCD_RS
set_instance_assignment -name SLEW_RATE 1 -to LCD_RW
set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to LCD_EN
set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to LCD_RS
set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to LCD_RW
set_global_assignment -name VHDL_FILE lcd_driver_hd44780_module.vhd
set_global_assignment -name VHDL_FILE tb_lcd_driver_hd44780_module.vhd
set_global_assignment -name COMMAND_MACRO_FILE tb_lcd_driver_hd44780_module.do
set_global_assignment -name VHDL_FILE example_driver.vhd
set_global_assignment -name VHDL_FILE tb_example_driver.vhd
set_global_assignment -name COMMAND_MACRO_FILE tb_example_driver.do
set_global_assignment -name SDC_FILE lcd_driver_hd44780.sdc
set_global_assignment -name TEXT_FILE readme.txt
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
/trunk/lcd_driver_hd44780.sdc
0,0 → 1,115
## Generated SDC file "lcd_driver_hd44780.sdc"
 
## Copyright (C) 1991-2011 Altera Corporation
## Your use of Altera Corporation's design tools, logic functions
## and other software and tools, and its AMPP partner logic
## functions, and any output files from any of the foregoing
## (including device programming or simulation files), and any
## associated documentation or information are expressly subject
## to the terms and conditions of the Altera Program License
## Subscription Agreement, Altera MegaCore Function License
## Agreement, or other applicable license agreement, including,
## without limitation, that your use is for the sole purpose of
## programming logic devices manufactured by Altera and sold by
## Altera or its authorized distributors. Please refer to the
## applicable agreement for further details.
 
 
## VENDOR "Altera"
## PROGRAM "Quartus II"
## VERSION "Version 11.1 Build 216 11/23/2011 Service Pack 1 SJ Web Edition"
 
## DATE "Thu Oct 11 15:50:30 2012"
 
##
## DEVICE "EP3C16F484C6"
##
 
 
#**************************************************************
# Time Information
#**************************************************************
 
set_time_format -unit ns -decimal_places 3
 
 
 
#**************************************************************
# Create Clock
#**************************************************************
 
create_clock -name {CLOCK_50} -period 20.000 -waveform { 0.000 10.000 } [get_ports {CLOCK_50}]
 
 
#**************************************************************
# Create Generated Clock
#**************************************************************
 
 
 
#**************************************************************
# Set Clock Latency
#**************************************************************
 
 
 
#**************************************************************
# Set Clock Uncertainty
#**************************************************************
 
#set_clock_uncertainty -rise_from [get_keepers {prescaler:pres|clkint}] -rise_to [get_keepers {prescaler:pres|clkint}] 0.020
#set_clock_uncertainty -rise_from [get_keepers {prescaler:pres|clkint}] -fall_to [get_keepers {prescaler:pres|clkint}] 0.020
#set_clock_uncertainty -fall_from [get_keepers {prescaler:pres|clkint}] -rise_to [get_keepers {prescaler:pres|clkint}] 0.020
#set_clock_uncertainty -fall_from [get_keepers {prescaler:pres|clkint}] -fall_to [get_keepers {prescaler:pres|clkint}] 0.020
 
set_clock_uncertainty -rise_from [get_clocks {CLOCK_50}] -rise_to [get_clocks {CLOCK_50}] 0.020
set_clock_uncertainty -rise_from [get_clocks {CLOCK_50}] -fall_to [get_clocks {CLOCK_50}] 0.020
set_clock_uncertainty -fall_from [get_clocks {CLOCK_50}] -rise_to [get_clocks {CLOCK_50}] 0.020
set_clock_uncertainty -fall_from [get_clocks {CLOCK_50}] -fall_to [get_clocks {CLOCK_50}] 0.020
 
#**************************************************************
# Set Input Delay
#**************************************************************
 
 
 
#**************************************************************
# Set Output Delay
#**************************************************************
 
 
 
#**************************************************************
# Set Clock Groups
#**************************************************************
 
 
 
#**************************************************************
# Set False Path
#**************************************************************
 
 
 
#**************************************************************
# Set Multicycle Path
#**************************************************************
 
 
 
#**************************************************************
# Set Maximum Delay
#**************************************************************
 
 
 
#**************************************************************
# Set Minimum Delay
#**************************************************************
 
 
 
#**************************************************************
# Set Input Transition
#**************************************************************
 
/trunk/photo.jpg Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
trunk/photo.jpg Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: trunk/tb_lcd_driver_hd44780_module.vhd =================================================================== --- trunk/tb_lcd_driver_hd44780_module.vhd (nonexistent) +++ trunk/tb_lcd_driver_hd44780_module.vhd (revision 5) @@ -0,0 +1,247 @@ +-- Filename: tb_lcd_driver_hd44780_module.do +-- Filetype: VHDL Testbench +-- Date: 26 oct 2012 +-- Update: - +-- Description: VHDL Testbench for simulation +-- Author: J. op den Brouw +-- State: Demo +-- Error: - +-- Version: 1.1alpha +-- Copyright: (c)2012, De Haagse Hogeschool + +-- This file contains a very simple VHDL testbench for a HD44780 LCD +-- display, see more specs at +-- +-- This VHDL code implements a simple testbench for testing +-- the LCD Module Driver. More scripting should be done here. + +-- The libraries et al. +library ieee; +use ieee.std_logic_1164.all; + +-- Empty entity +entity tb_lcd_driver_hd44780_module is +end entity tb_lcd_driver_hd44780_module; + +-- The testbench +architecture sim of tb_lcd_driver_hd44780_module is +-- The LCD driver +component lcd_driver_hd44780_module is + generic (freq : integer := 50000000; + areset_pol : std_logic := '1'; + time_init1 : time := 40 ms; + time_init2 : time := 4100 us; + time_init3 : time := 100 us; + time_tas : time := 60 ns; + time_cycle_e : time := 1000 ns; + time_pweh : time := 500 ns; + time_no_bf : time := 2 ms; + cursor_on : boolean := false; + blink_on : boolean := false; + use_bf : boolean := true + ); + port (clk : in std_logic; + areset : in std_logic; + -- User site + init : in std_logic; + data : in std_logic_vector(7 downto 0); + wr : in std_logic; + cls : in std_logic; + home : in std_logic; + goto10 : in std_logic; + goto20 : in std_logic; + goto30 : in std_logic; + busy : out std_logic; + -- LCD side + LCD_E : out std_logic; + LCD_RS : out std_logic; + LCD_RW : out std_logic; + LCD_DB : inout std_logic_vector(7 downto 0) + ); +end component lcd_driver_hd44780_module; + +-- Glue signals +signal clk : std_logic; +signal areset : std_logic; +-- User site +signal init : std_logic; +signal data : std_logic_vector(7 downto 0); +signal wr : std_logic; +signal cls : std_logic; +signal home : std_logic; +signal goto10 : std_logic; +signal goto20 : std_logic; +signal goto30 : std_logic; +signal busy : std_logic; +-- LCD side +signal LCD_DB : std_logic_vector(7 downto 0); +signal LCD_E : std_logic; +signal LCD_RW : std_logic; +signal LCD_RS : std_logic; + +--constant freq_in : integer := 10000; -- 10 kHz +constant freq_in : integer := 50000000; -- 50 MHz +constant clock_period : time := (1.0/real(freq_in)) * (1 sec); + +-- Internal tracer +signal trace : integer; + +-- Now let's begin... +begin + + -- Instantiation of the LCD Driver, some generics are used + lcdm : lcd_driver_hd44780_module + generic map (freq => freq_in, areset_pol => '1', time_cycle_e => 2000 ns, time_pweh => 500 ns, + cursor_on => true, blink_on => true, use_bf => false) + port map (clk => clk, areset => areset, init => init, data => data, wr => wr, cls => cls, + home => home, goto10 => goto10, goto20 => goto20, goto30 => goto30, busy => busy, + LCD_DB => LCD_DB, LCD_E => LCD_E, LCD_RW => LCD_RW, LCD_RS => LCD_RS); + + -- The clock signal generation process + clockgen: process is + begin + -- give time for reset + clk <= '0'; + areset <= '1'; + wait for 15 ns; + areset <= '0'; + wait for 5 ns; + -- forever: generate clock cycle for 20 ns and 50% d.c. + loop + clk <= '1'; + wait for clock_period/2; + clk <= '0'; + wait for clock_period/2; + end loop; + end process; + + -- Simulating the user side of the driver + user_side: process is + begin + -- All at zero + init <= '0'; + cls <= '0'; + home <= '0'; + goto10 <= '0'; + goto20 <= '0'; + goto30 <= '0'; + wr <= '0'; + data <= (others => '0'); + wait until clk = '1'; + + -- wait for initialization to complete + wait until busy = '0'; + + -- Write data to LCD + wait until clk = '1'; + data <= "01000011"; + wr <= '1'; + wait until clk = '1'; + wr <= '0'; + wait until busy = '0'; + wait until clk = '1'; + -- Write data to LCD + data <= "01000011"; + wr <= '1'; + wait until clk = '1'; + wr <= '0'; + wait until busy = '0'; + wait until clk = '1'; + + -- Clear the screen + wait until clk = '1'; + cls <= '1'; + wait until clk = '1'; + cls <= '0'; + wait until busy = '0'; + + -- Home the screen + wait until clk = '1'; + home <= '1'; + wait until clk = '1'; + home <= '0'; + wait until busy = '0'; + + -- Goto line + wait until clk = '1'; + goto10 <= '1'; + wait until clk = '1'; + goto10 <= '0'; + wait until busy = '0'; + wait until clk = '1'; + goto20 <= '1'; + wait until clk = '1'; + goto20 <= '0'; + wait until busy = '0'; + wait until clk = '1'; + goto30 <= '1'; + wait until clk = '1'; + goto30 <= '0'; + wait until busy = '0'; + + -- Write data to LCD + wait until clk = '1'; + wr <= '1'; + wait until clk = '1'; + wr <= '0'; + wait until busy = '0'; + wait until clk = '1'; + + -- Initialize the LCD + wait until clk = '1'; + init <= '1'; + wait until clk = '1'; + init <= '0'; + wait until busy = '0'; + wait until clk = '1'; + + wait; + end process; + + -- Simple simulation description of the LCD itself... + -- (probably too simple) + lcd_module_sim: process is + begin + trace <= 0; + LCD_DB <= (others => 'Z'); + -- Wait for reset clear + wait until areset = '0'; + trace <= 1; + -- Three writes to the LCD, no busy flag testing possible + wait until LCD_E = '1'; + wait until LCD_E = '1'; + wait until LCD_E = '1'; + trace <= 2; + + loop + -- command/data written to + trace <= 3; + wait until LCD_E = '1'; + trace <= 4; + wait until LCD_E = '0'; + + -- busy flag reading + trace <= 5; + wait until LCD_E = '1'; + trace <= 6; + if LCD_RW = '1' then + trace <= 61; + -- Signal LCD is busy + LCD_DB <= "1ZZZZZZZ"; + -- Internal delay of the LCD for some commands + wait for 40 us; + -- Signal LCD is ready + LCD_DB <= "0ZZZZZZZ"; + end if; + wait until LCD_E = '0'; + trace <= 7; + if LCD_RW = '1' then + trace <= 1; + LCD_DB <= "ZZZZZZZZ"; + end if; + + end loop; + wait; + end process; + +end architecture; \ No newline at end of file Index: trunk/tb_lcd_driver_hd44780_module.do =================================================================== --- trunk/tb_lcd_driver_hd44780_module.do (nonexistent) +++ trunk/tb_lcd_driver_hd44780_module.do (revision 5) @@ -0,0 +1,96 @@ +# Filename: tb_lcd_driver_hd44780_module.do +# Filetype: Modelsim Script File +# Date: 66 oct 2012 +# Update: - +# Description: Script File For Automatic Simulation +# Author: J. op den Brouw +# State: Demo +# Error: - +# Version: 1.1alpha +# Copyright: (c)2012, De Haagse Hogeschool + +# This ModelSim command file houses all commands for tracing +# the LCD Module Driver. + +# Set transcript on +transcript on + +# Recreate the work directory and map to work +if {[file exists rtl_work]} { + vdel -lib rtl_work -all +} +vlib rtl_work +vmap work rtl_work + +# Find out if we're started through Quartus or by hand +# (or by using an exec in the Tcl window in Quartus). +# Quartus has the annoying property that it will start +# Modelsim from a directory called "simulation/modelsim". +# The design and the testbench are located in the project +# root, so we've to compensate for that. +if [ string match "*simulation/modelsim" [pwd] ] { + set prefix "../../" + puts "Running Modelsim from Quartus..." +} else { + set prefix "" + puts "Running Modelsim..." +} + +# Compile the LCD VHDL description and testbench, +# please note that the design and its testbench is located +# in the project root, but the simulator start in directory +# /simulation/modelsim, so we have to compensate +# for that. +vcom -2008 -work work ${prefix}lcd_driver_hd44780_module.vhd +vcom -2008 -work work ${prefix}tb_lcd_driver_hd44780_module.vhd + +# Start the simulator with 1 ns time resolution +vsim -t 1ns -L rtl_work -L work -voptargs="+acc" tb_lcd_driver_hd44780_module + +# Log all signals in the design, good if the number +# of signals is small. +add log -r * + +# Add all toplevel signals +# Add a number of signals of the simulated design +#add list * + +# Add all toplevel signals +# Add a number of signals of the simulated design +add wave -divider "SYSTEM" +add wave clk +add wave areset +add wave -divider "Inputs" +add wave init +add wave cls +add wave home +add wave goto10 +add wave goto20 +add wave goto30 +add wave wr +add wave data +add wave -divider "Internals" +add wave lcdm/current_state +add wave lcdm/return_state +add wave lcdm/delay_counter +add wave lcdm/use_bf_int +add wave trace +add wave -divider "Outputs" +add wave busy +add wave LCD_E +add wave LCD_RW +add wave LCD_RS +add wave LCD_DB + +# Open Structure, Signals (waveform) and List window +view structure +#view list +view signals +view wave + +# Run simulation for ... +# Note: 60 ms is sufficient using Busy Flag reading. +run 160 ms + +# Fill up the waveform in the window +wave zoom full Index: trunk/readme.txt =================================================================== --- trunk/readme.txt (nonexistent) +++ trunk/readme.txt (revision 5) @@ -0,0 +1,104 @@ +Information to the Project HD44780 Driver +----------------------------------------- +This project contains VHDL descriptions for driving a standard HD44780 +LCD Driver with a minimum of inputs. Please read on. + +Information +----------- +Author: J.E.J. op den Brouw +Company: De Haagse Hogeschool +Rationale: This driver is written to facilitate my students +Software: Quartus II v11.1 / ModelSim v10.0.c / Windows 7 +Hardware: Terasic DE0 board with optional display (Cyclone III) +Status: Alpha, tested by my students. + +Files +----- +lcd_driver_hd44780_module.vhd - The Driver +tb_lcd_driver_hd44780_module.vhd - Simple testbench +tb_lcd_driver_hd44780_module.do - ModelSim command file +example_driver.vhd - Example on how to use the driver +tb_example_driver.vhd - Simple testbench +tb_example_driver.do - ModelSim command file +lcd_driver_hd44780.sdc - Synopsys Constraints File (clock info only) +readme.txt - This file + +Overall Description +---------------------------------------------------------------------------------------- +Currently, this driver uses the 8-bit databus mode. This is not a big problem +for most FPGA's because of the numerous pins. +Please note that there are a lot of almost-the-same displays available, so +it's not guaranteed to work with all displays available. Also, timing may differ. + +This code is tested on a Terasic DE0-board with an optional LCD display. +See the weblinks: +http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=364 +http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=78&No=396 +for more info. The display used has only two lines. + +The VHDL descriptions can both be simulated and synthesized. + +This driver has a User Side and a LCD Side. The user is to interface at the User Side +and has a number of "routines" at her disposal. The User Side implements the following +inputs/routines in order of priority: + +Command inputs: + init: a logic 1 initializes the display + cls: a logic 1 clears the display (and goes to home) + home: a logic 1 sets the cursor to row 0, column 0 + goto10: a logic 1 sets the cursor to row 1, column 0 + goto20: a logic 1 sets the cursor to row 2, column 0 + goto30: a logic 1 sets the cursor to row 3, column 0 + wr: a logic 1 writes a character to the display + +Data inputs: + + data: an 8-bit data to be written to the display + +The user has one observable output: + + busy: a logic 1 indicates that the driver is currently + busy driving the display, a logic 0 indicates that + the driver waits for the next command. + +The user can supply the next generics, which are processed at +instantiation of the module: + + freq: the clock frequency at which the hardware has to run. + this frequency is mandatory because of internal delays + calculated, defaults to 50 MHz. + areset_pol: + the polarity of the reset signal, defaults to High (1) + time_init1: + the time to wait after Vcc > 4.5 V + time_init2: + the time to wait after first "contact" + time_init3: + the time to wait after the second contact + time_tas: + the RW and RS signal setup time with respect to the positive + edge of the E pulse + time_cycle_e: + the complete cycle time + time_pweh: + the E pulse width high time + time_no_bf: + time to wait before command completion if no Busy Flag reading is done, + some designs connect RW to logic 0, so reading from the LCD is not + possible, saves a pin. + cursor_on: + true to set the cursor on at the display, false for no cursor + blink_on: + true to let the cursor blink, false for no blink (just a underscore) + use_bf: true if Busy Flag reading is to be used, false for no BF reading + +Note: it's not possible to write command codes to the display. + +A note about timing: + Some of the timing parameters are very small, e.g. the RW and RS setup time with + respect to rising edge of E. If the clock frequency is too low, the delay calculated + will be zero, which result in at least a delay with the period time of the clock. + +A note about implementing: + If the driver doesn't work or you get clobbered strings, please use non-BF + reading at first. Next, increase the Cycle E time and PWeh time. Index: trunk/tb_example_driver.vhd =================================================================== --- trunk/tb_example_driver.vhd (nonexistent) +++ trunk/tb_example_driver.vhd (revision 5) @@ -0,0 +1,150 @@ +-- Filename: tb_example_driver.vhd +-- Filetype: VHDL Testbench +-- Date: 26 oct 2012 +-- Update: - +-- Description: VHDL testbench for example driver +-- Author: J. op den Brouw +-- State: Demo +-- Error: - +-- Version: 1.0alpha +-- Copyright: (c)2012, De Haagse Hogeschool + +-- This file contains a very simple VHDL testbench for a User Side +-- driver for the LCD driver. +-- + +-- Libraries et al. +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- The entity of a testbench for the example driver +entity tb_example_driver is +end entity tb_example_driver; + +-- The architecture! +architecture sim of tb_example_driver is +-- Component declaration of the example driver +component example_driver is + port (CLOCK_50 : in std_logic; + BUTTON : in std_logic_vector(2 downto 0); + SW : in std_logic_vector(9 downto 0); + LEDG : out std_logic_vector(9 downto 0); + HEX3_D : out std_logic_vector(6 downto 0); + HEX2_D : out std_logic_vector(6 downto 0); + HEX1_D : out std_logic_vector(6 downto 0); + HEX0_D : out std_logic_vector(6 downto 0); + HEX0_DP : out std_logic; + HEX1_DP : out std_logic; + HEX2_DP : out std_logic; + HEX3_DP : out std_logic; + -- LCD of the DE0 board + LCD_EN : out std_logic; + LCD_RS : out std_logic; + LCD_RW : out std_logic; + LCD_DATA : inout std_logic_vector(7 downto 0); + LCD_BLON : out std_logic + ); +end component example_driver; + +signal CLOCK_50 : std_logic; +signal BUTTON : std_logic_vector(2 downto 0); +signal SW : std_logic_vector(9 downto 0); +signal LEDG : std_logic_vector(9 downto 0); +signal HEX3_D : std_logic_vector(6 downto 0); +signal HEX2_D : std_logic_vector(6 downto 0); +signal HEX1_D : std_logic_vector(6 downto 0); +signal HEX0_D : std_logic_vector(6 downto 0); +signal HEX0_DP : std_logic; +signal HEX1_DP : std_logic; +signal HEX2_DP : std_logic; +signal HEX3_DP : std_logic; +-- LCD of the DE0 board +signal LCD_EN : std_logic; +signal LCD_RS : std_logic; +signal LCD_RW : std_logic; +signal LCD_DATA : std_logic_vector(7 downto 0); +signal LCD_BLON : std_logic; + +--constant freq_in : integer := 10000; -- 10 kHz +constant freq_in : integer := 50000000; -- 50 MHz +constant clock_period : time := (1.0/real(freq_in)) * (1 sec); + +-- Internal tracer +signal trace : integer; + +begin + + -- The driver's driver... + de0: example_driver + port map (CLOCK_50 => CLOCK_50, BUTTON => BUTTON, SW => SW, LEDG => LEDG, + HEX3_D => HEX3_D, HEX2_D => HEX2_D, HEX1_D => HEX1_D, HEX0_D => HEX0_D, + HEX0_DP => HEX0_DP, HEX1_DP => HEX1_DP, HEX2_DP => HEX2_DP, HEX3_DP => HEX3_DP, + LCD_EN => LCD_EN, LCD_RS => LCD_RS, LCD_RW => LCD_RW, LCD_DATA => LCD_DATA, + LCD_BLON => LCD_BLON); + + -- The clock signal generation process + clockgen: process is + begin + -- give time for reset, buttons active low! + CLOCK_50 <= '0'; + BUTTON <= "110"; + wait for 15 ns; + BUTTON <= "111"; + wait for 5 ns; + -- forever: generate clock cycle for 20 ns and 50% d.c. + loop + CLOCK_50 <= '1'; + wait for clock_period/2; + CLOCK_50 <= '0'; + wait for clock_period/2; + end loop; + end process; + + -- Simple simulation description of the LCD itself... + -- (probably too simple) + lcd_module_sim: process is + begin + trace <= 0; + LCD_DATA <= (others => 'Z'); + -- Wait for reset clear + wait until BUTTON(0) = '0'; + trace <= 1; + -- Three writes to the LCD, no busy flag testing possible + wait until LCD_EN = '1'; + wait until LCD_EN = '1'; + wait until LCD_EN = '1'; + trace <= 2; + + loop + -- command/data written to + trace <= 3; + wait until LCD_EN = '1'; + trace <= 4; + wait until LCD_EN = '0'; + + -- busy flag reading + trace <= 5; + wait until LCD_EN = '1'; + trace <= 6; + if LCD_RW = '1' then + trace <= 61; + -- Signal LCD is busy + LCD_DATA <= "1ZZZZZZZ"; + -- Internal delay of the LCD for some commands + wait for 40 us; + -- Signal LCD is ready + LCD_DATA <= "0ZZZZZZZ"; + end if; + wait until LCD_EN = '0'; + trace <= 7; + if LCD_RW = '1' then + trace <= 1; + LCD_DATA <= "ZZZZZZZZ"; + end if; + + end loop; + wait; + end process; + +end architecture sim; \ No newline at end of file Index: trunk/tb_example_driver.do =================================================================== --- trunk/tb_example_driver.do (nonexistent) +++ trunk/tb_example_driver.do (revision 5) @@ -0,0 +1,93 @@ +# Filename: tb_example_driver.do +# Filetype: Modelsim Script File +# Date: 26 oct 2012 +# Update: - +# Description: Script File For Automatic Simulation +# Author: J. op den Brouw +# State: Demo +# Error: - +# Version: 1.1aplha +# Copyright: (c)2012, De Haagse Hogeschool + +# This ModelSim command file houses all commands for tracing +# the client side module driver alias the test hardware. + +# Set transcript on +transcript on + +# Recreate the work directory and map to work +if {[file exists rtl_work]} { + vdel -lib rtl_work -all +} +vlib rtl_work +vmap work rtl_work + +# Find out if we're started through Quartus or by hand +# (or by using an exec in the Tcl window in Quartus). +# Quartus has the annoying property that it will start +# Modelsim from a directory called "simulation/modelsim". +# The design and the testbench are located in the project +# root, so we've to compensate for that. +if [ string match "*simulation/modelsim" [pwd] ] { + set prefix "../../" + puts "Running Modelsim from Quartus..." +} else { + set prefix "" + puts "Running Modelsim..." +} + +# Compile the LCD VHDL description and testbench, +# please note that the design and its testbench are located +# in the project root, but the simulator start in directory +# /simulation/modelsim, so we have to compensate +# for that. +vcom -2008 -work work ${prefix}lcd_driver_hd44780_module.vhd +vcom -2008 -work work ${prefix}example_driver.vhd +vcom -2008 -work work ${prefix}tb_example_driver.vhd + +# Start the simulator with 1 ns time resolution +vsim -t 1ns -L rtl_work -L work -voptargs="+acc" tb_example_driver + +# Log all signals in the design, good if the number +# of signals is small. +add log -r * + +# Add all toplevel signals +# Add a number of signals of the simulated design +add wave -divider "SYSTEM" +add wave CLOCK_50 +add wave -divider "Inputs" +add wave BUTTON +add wave -divider "Internals" +add wave de0/areset +add wave de0/clk +add wave de0/state +add wave de0/busy +add wave de0/wr +add wave de0/goto10 +add wave de0/goto20 +add wave de0/goto30 +add wave de0/home +add wave de0/cls +add wave de0/line_counter +add wave de0/character_counter +add wave -divider "Outputs" +add wave LCD_EN +add wave LCD_RW +add wave LCD_RS +add wave LCD_DATA +add wave LEDG(0) + +# Open Structure, Signals (waveform) and List window +view structure +#view list +view signals +view wave + +# Run simulation for ... +# Note 60 ms is sufficient if using Busy Flag reading, 270 ms +# for non-BF reading +run 270 ms + +# Fill up the waveform in the window +wave zoom full

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.