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
/
- from Rev 5 to Rev 6
- ↔ Reverse comparison
Rev 5 → Rev 6
/hd44780_driver/trunk/trunk/example_driver.vhd
File deleted
\ No newline at end of file
/hd44780_driver/trunk/trunk/lcd_driver_hd44780.qsf
File deleted
\ No newline at end of file
/hd44780_driver/trunk/trunk/lcd_driver_hd44780.sdc
File deleted
/hd44780_driver/trunk/trunk/photo.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
hd44780_driver/trunk/trunk/photo.jpg
Property changes :
Deleted: svn:mime-type
## -1 +0,0 ##
-application/octet-stream
\ No newline at end of property
Index: hd44780_driver/trunk/trunk/tb_lcd_driver_hd44780_module.vhd
===================================================================
--- hd44780_driver/trunk/trunk/tb_lcd_driver_hd44780_module.vhd (revision 5)
+++ hd44780_driver/trunk/trunk/tb_lcd_driver_hd44780_module.vhd (nonexistent)
@@ -1,247 +0,0 @@
--- 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: hd44780_driver/trunk/trunk/tb_lcd_driver_hd44780_module.do
===================================================================
--- hd44780_driver/trunk/trunk/tb_lcd_driver_hd44780_module.do (revision 5)
+++ hd44780_driver/trunk/trunk/tb_lcd_driver_hd44780_module.do (nonexistent)
@@ -1,96 +0,0 @@
-# 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: hd44780_driver/trunk/trunk/readme.txt
===================================================================
--- hd44780_driver/trunk/trunk/readme.txt (revision 5)
+++ hd44780_driver/trunk/trunk/readme.txt (nonexistent)
@@ -1,104 +0,0 @@
-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: hd44780_driver/trunk/trunk/tb_example_driver.vhd
===================================================================
--- hd44780_driver/trunk/trunk/tb_example_driver.vhd (revision 5)
+++ hd44780_driver/trunk/trunk/tb_example_driver.vhd (nonexistent)
@@ -1,150 +0,0 @@
--- 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: hd44780_driver/trunk/trunk/tb_example_driver.do
===================================================================
--- hd44780_driver/trunk/trunk/tb_example_driver.do (revision 5)
+++ hd44780_driver/trunk/trunk/tb_example_driver.do (nonexistent)
@@ -1,93 +0,0 @@
-# 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
Index: hd44780_driver/trunk/trunk/lcd_driver_hd44780_module.vhd
===================================================================
--- hd44780_driver/trunk/trunk/lcd_driver_hd44780_module.vhd (revision 5)
+++ hd44780_driver/trunk/trunk/lcd_driver_hd44780_module.vhd (nonexistent)
@@ -1,500 +0,0 @@
--- 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:
--- 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.
---
--- 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;
Index: hd44780_driver/trunk/trunk/lcd_driver_hd44780.qpf
===================================================================
--- hd44780_driver/trunk/trunk/lcd_driver_hd44780.qpf (revision 5)
+++ hd44780_driver/trunk/trunk/lcd_driver_hd44780.qpf (nonexistent)
@@ -1,30 +0,0 @@
-# -------------------------------------------------------------------------- #
-#
-# 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"