1 |
2 |
jodb |
-- Filename: lcd_driver_hd44780_module.vhd
|
2 |
|
|
-- Filetype: VHDL Source Code
|
3 |
|
|
-- Date: 26 oct 2012
|
4 |
|
|
-- Update: -
|
5 |
|
|
-- Description: VHDL Description for driving an HD44780 based LCD driver
|
6 |
|
|
-- Author: J. op den Brouw
|
7 |
|
|
-- State: Demo
|
8 |
|
|
-- Error: -
|
9 |
|
|
-- Version: 1.2alpha
|
10 |
|
|
-- Copyright: (c)2012, De Haagse Hogeschool
|
11 |
|
|
|
12 |
|
|
-- This file contains a VHDL description for driving an HD44780 based LCD
|
13 |
|
|
-- driver, see for a standard information of such a display:
|
14 |
|
|
-- https://decibel.ni.com/content/servlet/JiveServlet/download/2741-3-3217/hd44780.pdf
|
15 |
|
|
--
|
16 |
|
|
-- Currently, this driver uses the 8-bit databus mode. This is not a big problem
|
17 |
|
|
-- for most FPGA's because of the numerous pins.
|
18 |
|
|
--
|
19 |
|
|
-- Please note that there are a lot of almost-the-same displays available, so
|
20 |
|
|
-- it's not guaranteed to work with all displays available. Also, timing may differ.
|
21 |
|
|
--
|
22 |
|
|
-- This code is tested on a Terasic DE0-board with an optional
|
23 |
|
|
-- LCD display. See the weblinks
|
24 |
|
|
-- http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=56&No=364
|
25 |
|
|
-- http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=78&No=396
|
26 |
|
|
-- for more info. The display used has only two lines.
|
27 |
|
|
--
|
28 |
3 |
jodb |
-- This VHDL description can both be simulated and synthesized.
|
29 |
2 |
jodb |
--
|
30 |
|
|
-- This driver has a User Side and a LCD Side. The user is to interface at the User Side
|
31 |
|
|
-- and has a number of "routines" at her disposal. The User Side implements the following
|
32 |
|
|
-- inputs/routines in order of priority:
|
33 |
|
|
--
|
34 |
|
|
-- Command inputs:
|
35 |
|
|
-- init: a logic 1 initializes the display
|
36 |
|
|
-- cls: a logic 1 clears the display (and goes to home)
|
37 |
|
|
-- home: a logic 1 sets the cursor to row 0, column 0
|
38 |
|
|
-- goto10: a logic 1 sets the cursor to row 1, column 0
|
39 |
|
|
-- goto20: a logic 1 sets the cursor to row 2, column 0
|
40 |
|
|
-- goto30: a logic 1 sets the cursor to row 3, column 0
|
41 |
|
|
-- wr: a logic 1 writes a character to the display
|
42 |
|
|
--
|
43 |
|
|
-- Data inputs:
|
44 |
|
|
--
|
45 |
|
|
-- data: an 8-bit data to be written to the display
|
46 |
|
|
--
|
47 |
|
|
-- The user has one observable output:
|
48 |
|
|
--
|
49 |
|
|
-- busy: a logic 1 indicates that the driver is currently
|
50 |
|
|
-- busy driving the display, a logic 0 indicates that
|
51 |
|
|
-- the driver waits for the next command.
|
52 |
|
|
--
|
53 |
|
|
-- The user can supply the next generics, which are processed at
|
54 |
|
|
-- instantiation of the module:
|
55 |
|
|
--
|
56 |
|
|
-- freq: the clock frequency at which the hardware has to run.
|
57 |
|
|
-- this frequency is mandatory because of internal delays
|
58 |
|
|
-- calculated, defaults to 50 MHz.
|
59 |
|
|
-- areset_pol:
|
60 |
|
|
-- the polarity of the reset signal, defaults to High (1)
|
61 |
|
|
-- time_init1:
|
62 |
|
|
-- the time to wait after Vcc > 4.5 V
|
63 |
|
|
-- time_init2:
|
64 |
|
|
-- the time to wait after first "contact"
|
65 |
|
|
-- time_init3:
|
66 |
|
|
-- the time to wait after the second contact
|
67 |
|
|
-- time_tas:
|
68 |
|
|
-- the RW and RS signal setup time with respect to the positive
|
69 |
|
|
-- edge of the E pulse
|
70 |
|
|
-- time_cycle_e:
|
71 |
|
|
-- the complete cycle time
|
72 |
|
|
-- time_pweh:
|
73 |
|
|
-- the E pulse width high time
|
74 |
|
|
-- time_no_bf:
|
75 |
|
|
-- time to wait before command completion if no Busy Flag reading is done,
|
76 |
|
|
-- some designs connect RW to logic 0, so reading from the LCD is not
|
77 |
|
|
-- possible, saves a pin.
|
78 |
|
|
-- cursor_on:
|
79 |
|
|
-- true to set the cursor on at the display, false for no cursor
|
80 |
|
|
-- blink_on:
|
81 |
|
|
-- true to let the cursor blink, false for no blink (just a underscore)
|
82 |
|
|
-- use_bf: true if Busy Flag reading is to be used, false for no BF reading
|
83 |
|
|
--
|
84 |
|
|
-- Note: it's not possible to write command codes to the display.
|
85 |
|
|
--
|
86 |
|
|
-- Changes to v1.0: LCD_E is renamed to LCD_EN
|
87 |
|
|
-- LCD_DB is renamed to LCD_DATA
|
88 |
|
|
-- busy is now registered
|
89 |
|
|
-- removed hardware simulation architecture
|
90 |
|
|
--
|
91 |
|
|
-- Changes to v1.1: added timing generics for better steering of the E pulse cycle
|
92 |
|
|
-- implemented cursor on/off/blink with generic parameters
|
93 |
|
|
--
|
94 |
|
|
-- Changes to v1.2: added Busy Flag reading mode, selectable at instantiation time
|
95 |
|
|
-- LCD_EN changes back to LCD_E
|
96 |
|
|
-- LCD_DATA changed back to LCD_DB
|
97 |
|
|
--
|
98 |
|
|
-- To do: use 4-bit mode or 8-bit mode at instantiation time
|
99 |
|
|
--
|
100 |
|
|
|
101 |
|
|
-- The libraries to use.
|
102 |
|
|
library ieee;
|
103 |
|
|
use ieee.std_logic_1164.all;
|
104 |
|
|
|
105 |
|
|
-- The entity of the LCD Driver Module.
|
106 |
|
|
entity lcd_driver_hd44780_module is
|
107 |
|
|
generic (freq : integer := 50000000;
|
108 |
|
|
areset_pol : std_logic := '1';
|
109 |
|
|
time_init1 : time := 40 ms;
|
110 |
|
|
time_init2 : time := 4100 us;
|
111 |
|
|
time_init3 : time := 100 us;
|
112 |
|
|
time_tas : time := 60 ns;
|
113 |
|
|
time_cycle_e : time := 1000 ns;
|
114 |
|
|
time_pweh : time := 500 ns;
|
115 |
|
|
time_no_bf : time := 2 ms;
|
116 |
|
|
cursor_on : boolean := false;
|
117 |
|
|
blink_on : boolean := false;
|
118 |
|
|
use_bf : boolean := true
|
119 |
|
|
);
|
120 |
|
|
port (clk : in std_logic;
|
121 |
|
|
areset : in std_logic;
|
122 |
|
|
-- User site
|
123 |
|
|
init : in std_logic;
|
124 |
|
|
data : in std_logic_vector(7 downto 0);
|
125 |
|
|
wr : in std_logic;
|
126 |
|
|
cls : in std_logic;
|
127 |
|
|
home : in std_logic;
|
128 |
|
|
goto10 : in std_logic;
|
129 |
|
|
goto20 : in std_logic;
|
130 |
|
|
goto30 : in std_logic;
|
131 |
|
|
busy : out std_logic;
|
132 |
|
|
-- LCD side
|
133 |
|
|
LCD_E : out std_logic;
|
134 |
|
|
LCD_RS : out std_logic;
|
135 |
|
|
LCD_RW : out std_logic;
|
136 |
|
|
LCD_DB : inout std_logic_vector(7 downto 0)
|
137 |
|
|
);
|
138 |
|
|
end entity lcd_driver_hd44780_module;
|
139 |
|
|
|
140 |
|
|
-- This architecture drives the LCD.
|
141 |
|
|
architecture hardware_driver of lcd_driver_hd44780_module is
|
142 |
|
|
|
143 |
|
|
-- Delays... Please note that if the frequency is (too) low,
|
144 |
|
|
-- some of the delays will 0. The code will take care of that.
|
145 |
|
|
-- Converting time to integer is problematic. Please note the use of
|
146 |
|
|
-- the simulator time step in the calculations.
|
147 |
|
|
-- The simulator timestep
|
148 |
|
|
constant simulator_timestep : time := 1 ns;
|
149 |
|
|
-- Number of simulator timesteps per second.
|
150 |
|
|
constant sim_steps_per_sec : real := real(1 sec/simulator_timestep);
|
151 |
|
|
|
152 |
|
|
constant delay_init1 : integer := integer( real(freq) * real(time_init1/simulator_timestep) / sim_steps_per_sec);
|
153 |
|
|
constant delay_init2 : integer := integer( real(freq) * real(time_init2/simulator_timestep) / sim_steps_per_sec);
|
154 |
|
|
constant delay_init3 : integer := integer( real(freq) * real(time_init3/simulator_timestep) / sim_steps_per_sec);
|
155 |
|
|
constant delay_tas : integer := integer( real(freq) * real(time_tas/simulator_timestep) / sim_steps_per_sec);
|
156 |
|
|
constant delay_cycle_e : integer := integer( real(freq) * real(time_cycle_e/simulator_timestep) / sim_steps_per_sec);
|
157 |
|
|
constant delay_pweh : integer := integer( real(freq) * real(time_pweh/simulator_timestep) / sim_steps_per_sec);
|
158 |
|
|
constant delay_no_bf : integer := integer( real(freq) * real(time_no_bf/simulator_timestep) / sim_steps_per_sec);
|
159 |
|
|
|
160 |
|
|
-- The next statements do work in Quartus but not in (32 bit) ModelSim...
|
161 |
|
|
--constant delay_init1 : integer := integer(real(freq)*real(time'pos(time_init1)) / real(time'pos(1 sec)));
|
162 |
|
|
--constant delay_init2 : integer := integer(real(freq)*real(time'pos(time_init2)) / real(time'pos(1 sec)));
|
163 |
|
|
--constant delay_init3 : integer := integer(real(freq)*real(time'pos(time_init3)) / real(time'pos(1 sec)));
|
164 |
|
|
--constant delay_tas : integer := integer(real(freq)*real(time'pos(time_tas)) / real(time'pos(1 sec)));
|
165 |
|
|
--constant delay_cycle_e : integer := integer(real(freq)*real(time'pos(time_cycle_e)) / real(time'pos(1 sec)));
|
166 |
|
|
--constant delay_pweh : integer := integer(real(freq)*real(time'pos(time_pweh)) / real(time'pos(1 sec)));
|
167 |
|
|
--constant delay_no_bf : integer := integer(real(freq)*real(time'pos(time_no_bf)) / real(time'pos(1 sec)));
|
168 |
|
|
|
169 |
|
|
-- Time the E signal must be low following E high
|
170 |
|
|
constant delay_pwel : integer := delay_cycle_e-delay_pweh;
|
171 |
|
|
|
172 |
|
|
-- Counter for the delays. Timer would be a better choice.
|
173 |
|
|
-- Range should be to the longest delay.
|
174 |
|
|
signal delay_counter : integer range 0 to delay_init1;
|
175 |
|
|
|
176 |
|
|
-- Should we use Busy Flag reading?
|
177 |
|
|
signal use_bf_int : std_logic;
|
178 |
|
|
|
179 |
|
|
-- The states of the state machine.
|
180 |
|
|
type state_type is (reset, command_init, command_init_1, command_init_2, command_init_3,
|
181 |
|
|
command_init_4, command_init_5, command_init_6, command_init_7, command_init_8,
|
182 |
|
|
command_init_9, command_init_10, command_init_11, command_init12,
|
183 |
|
|
wait_for_command,
|
184 |
|
|
command_cls, command_home,
|
185 |
|
|
command_goto10, command_goto20, command_goto30, command_wr,
|
186 |
|
|
pulse_e, pulse_e_1, pulse_e_2, pulse_e_3, pulse_e_4,
|
187 |
|
|
pulse_busy_flag, pulse_busy_flag_1, pulse_busy_flag_2, pulse_busy_flag_3,
|
188 |
|
|
pulse_busy_flag_4, pulse_busy_flag_5);
|
189 |
|
|
|
190 |
|
|
|
191 |
|
|
-- The current state and one for the return state (to facilitate return to the caller).
|
192 |
|
|
signal current_state, return_state : state_type;
|
193 |
|
|
begin
|
194 |
|
|
|
195 |
|
|
-- The state machine ;-)
|
196 |
|
|
nsl_state: process (clk, areset) is
|
197 |
|
|
-- Function to translate a boolean to std_logic
|
198 |
|
|
function bool_to_stdlogic(l: boolean) return std_logic is
|
199 |
|
|
begin
|
200 |
|
|
if l then
|
201 |
|
|
return('1');
|
202 |
|
|
else
|
203 |
|
|
return('0');
|
204 |
|
|
end if;
|
205 |
|
|
end function bool_to_stdlogic;
|
206 |
|
|
begin
|
207 |
|
|
if (areset = '1' and areset_pol = '1') or (areset = '0' and areset_pol = '0') then
|
208 |
|
|
current_state <= reset;
|
209 |
|
|
delay_counter <= 0;
|
210 |
|
|
busy <= '1';
|
211 |
|
|
LCD_DB <= (others => 'Z');
|
212 |
|
|
LCD_E <= '0';
|
213 |
|
|
LCD_RS <= '0';
|
214 |
|
|
LCD_RW <= '0';
|
215 |
|
|
use_bf_int <= '0';
|
216 |
|
|
elsif rising_edge(clk) then
|
217 |
|
|
-- Default is busy
|
218 |
|
|
busy <= '1';
|
219 |
|
|
-- Default values of the LCD side
|
220 |
|
|
LCD_E <= '0';
|
221 |
|
|
LCD_RW <= '0';
|
222 |
|
|
case current_state is
|
223 |
|
|
when reset|command_init =>
|
224 |
|
|
-- The logic is reset. Start initialization routine.
|
225 |
|
|
LCD_DB <= (others => 'Z');
|
226 |
|
|
LCD_RS <= '0';
|
227 |
|
|
use_bf_int <= '0';
|
228 |
|
|
delay_counter <= delay_init1;
|
229 |
|
|
current_state <= command_init_1;
|
230 |
|
|
when command_init_1 =>
|
231 |
|
|
-- Wait until Vcc > 4.5 V...
|
232 |
|
|
LCD_DB <= (others => 'Z');
|
233 |
|
|
LCD_RS <= '0';
|
234 |
|
|
use_bf_int <= '0';
|
235 |
|
|
-- If done write 0x30 to the LCD
|
236 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
237 |
|
|
LCD_DB <= "00110000"; -- 0x30
|
238 |
|
|
current_state <= pulse_e;
|
239 |
|
|
return_state <= command_init_2;
|
240 |
|
|
else
|
241 |
|
|
delay_counter <= delay_counter-1;
|
242 |
|
|
end if;
|
243 |
|
|
when command_init_2 =>
|
244 |
|
|
-- Next, set up wait for 4.1 ms
|
245 |
|
|
LCD_DB <= (others => 'Z');
|
246 |
|
|
LCD_RS <= '0';
|
247 |
|
|
use_bf_int <= '0';
|
248 |
|
|
delay_counter <= delay_init2;
|
249 |
|
|
current_state <= command_init_3;
|
250 |
|
|
when command_init_3 =>
|
251 |
|
|
-- Wait...
|
252 |
|
|
LCD_DB <= (others => 'Z');
|
253 |
|
|
LCD_RS <= '0';
|
254 |
|
|
use_bf_int <= '0';
|
255 |
|
|
-- If done write 0x30 to the LCD
|
256 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
257 |
|
|
LCD_DB <= "00110000"; -- 0x30
|
258 |
|
|
current_state <= pulse_e;
|
259 |
|
|
return_state <= command_init_4;
|
260 |
|
|
else
|
261 |
|
|
delay_counter <= delay_counter-1;
|
262 |
|
|
end if;
|
263 |
|
|
when command_init_4 =>
|
264 |
|
|
-- Next, set up wait for 100 us
|
265 |
|
|
LCD_DB <= (others => 'Z');
|
266 |
|
|
LCD_RS <= '0';
|
267 |
|
|
use_bf_int <= '0';
|
268 |
|
|
delay_counter <= delay_init3;
|
269 |
|
|
current_state <= command_init_5;
|
270 |
|
|
when command_init_5 =>
|
271 |
|
|
-- Wait...
|
272 |
|
|
LCD_DB <= (others => 'Z');
|
273 |
|
|
LCD_RS <= '0';
|
274 |
|
|
use_bf_int <= '0';
|
275 |
|
|
-- If done write 0x30 to the LCD
|
276 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
277 |
|
|
LCD_DB <= "00110000"; -- 0x30
|
278 |
|
|
current_state <= pulse_e;
|
279 |
|
|
return_state <= command_init_6;
|
280 |
|
|
else
|
281 |
|
|
delay_counter <= delay_counter-1;
|
282 |
|
|
end if;
|
283 |
|
|
when command_init_6 =>
|
284 |
|
|
-- Power up is now done, so let's enter some reasonable values...
|
285 |
|
|
LCD_DB <= "00110000";
|
286 |
|
|
LCD_RS <= '0';
|
287 |
|
|
use_bf_int <= bool_to_stdlogic(use_bf);
|
288 |
|
|
current_state <= pulse_e;
|
289 |
|
|
return_state <= command_init_7;
|
290 |
|
|
when command_init_7 =>
|
291 |
|
|
-- 8-bit bus, 2(?) lines, 5x7 characters
|
292 |
|
|
LCD_DB <= "00111100"; -- 0x3C
|
293 |
|
|
LCD_RS <= '0';
|
294 |
|
|
current_state <= pulse_e;
|
295 |
|
|
return_state <= command_init_8;
|
296 |
|
|
when command_init_8 =>
|
297 |
|
|
-- Display off
|
298 |
|
|
LCD_DB <= "00001000"; -- 0x08
|
299 |
|
|
LCD_RS <= '0';
|
300 |
|
|
current_state <= pulse_e;
|
301 |
|
|
return_state <= command_init_9;
|
302 |
|
|
when command_init_9 =>
|
303 |
|
|
-- Display clear
|
304 |
|
|
LCD_DB <= "00000001"; -- 0x01
|
305 |
|
|
LCD_RS <= '0';
|
306 |
|
|
current_state <= pulse_e;
|
307 |
|
|
return_state <= command_init_10;
|
308 |
|
|
when command_init_10 =>
|
309 |
|
|
-- Display on, cursor and blink...
|
310 |
|
|
LCD_DB <= "000011" & bool_to_stdlogic(cursor_on) & bool_to_stdlogic(blink_on); -- 0x0C + ...
|
311 |
|
|
LCD_RS <= '0';
|
312 |
|
|
current_state <= pulse_e;
|
313 |
|
|
return_state <= command_init_11;
|
314 |
|
|
when command_init_11 =>
|
315 |
|
|
-- Mode set, increment cursor address, cursor shift
|
316 |
|
|
LCD_DB <= "00000110"; -- 0x06
|
317 |
|
|
LCD_RS <= '0';
|
318 |
|
|
current_state <= pulse_e;
|
319 |
|
|
return_state <= wait_for_command;
|
320 |
|
|
|
321 |
|
|
-- The command dispatcher! This state waits for one of
|
322 |
|
|
-- the command inputs to be logic '1' and 'starts' the
|
323 |
|
|
-- accompanying routine. Note the priority encoding!
|
324 |
|
|
when wait_for_command =>
|
325 |
|
|
LCD_DB <= (others => 'Z');
|
326 |
|
|
LCD_RS <= '0';
|
327 |
|
|
busy <= '0';
|
328 |
|
|
if init = '1' then
|
329 |
|
|
busy <= '1';
|
330 |
|
|
current_state <= command_init;
|
331 |
|
|
elsif cls = '1' then
|
332 |
|
|
busy <= '1';
|
333 |
|
|
current_state <= command_cls;
|
334 |
|
|
elsif home = '1' then
|
335 |
|
|
busy <= '1';
|
336 |
|
|
current_state <= command_home;
|
337 |
|
|
elsif goto10 = '1' then
|
338 |
|
|
busy <= '1';
|
339 |
|
|
current_state <= command_goto10;
|
340 |
|
|
elsif goto20 = '1' then
|
341 |
|
|
busy <= '1';
|
342 |
|
|
current_state <= command_goto20;
|
343 |
|
|
elsif goto30 = '1' then
|
344 |
|
|
busy <= '1';
|
345 |
|
|
current_state <= command_goto30;
|
346 |
|
|
elsif wr = '1' then
|
347 |
|
|
-- Read in data! Do NOT forget that here!
|
348 |
|
|
LCD_DB <= data;
|
349 |
|
|
busy <= '1';
|
350 |
|
|
current_state <= command_wr;
|
351 |
|
|
end if;
|
352 |
|
|
|
353 |
|
|
when command_cls =>
|
354 |
|
|
-- Display clear
|
355 |
|
|
LCD_DB <= "00000001";
|
356 |
|
|
LCD_RS <= '0';
|
357 |
|
|
current_state <= pulse_e;
|
358 |
|
|
return_state <= wait_for_command;
|
359 |
|
|
|
360 |
|
|
when command_home =>
|
361 |
|
|
-- Cursor home
|
362 |
|
|
LCD_DB <= "00000010";
|
363 |
|
|
LCD_RS <= '0';
|
364 |
|
|
current_state <= pulse_e;
|
365 |
|
|
return_state <= wait_for_command;
|
366 |
|
|
|
367 |
|
|
when command_goto10 =>
|
368 |
|
|
-- Cursor to beginning of line 2nd line...
|
369 |
|
|
LCD_DB <= "11000000"; --0x80+0x40;
|
370 |
|
|
LCD_RS <= '0';
|
371 |
|
|
current_state <= pulse_e;
|
372 |
|
|
return_state <= wait_for_command;
|
373 |
|
|
|
374 |
|
|
when command_goto20 =>
|
375 |
|
|
-- Cursor to beginning of line 3rd line...
|
376 |
|
|
LCD_DB <= "10010000"; --0x80+0x10;
|
377 |
|
|
LCD_RS <= '0';
|
378 |
|
|
current_state <= pulse_e;
|
379 |
|
|
return_state <= wait_for_command;
|
380 |
|
|
|
381 |
|
|
when command_goto30 =>
|
382 |
|
|
-- Cursor to beginning of line 4th line...
|
383 |
|
|
LCD_DB <= "11010000"; --0x80+0x50;
|
384 |
|
|
LCD_RS <= '0';
|
385 |
|
|
current_state <= pulse_e;
|
386 |
|
|
return_state <= wait_for_command;
|
387 |
|
|
|
388 |
|
|
when command_wr =>
|
389 |
|
|
-- Start character write cycle
|
390 |
|
|
-- Do NOT set data here!
|
391 |
|
|
LCD_RS <= '1';
|
392 |
|
|
current_state <= pulse_e;
|
393 |
|
|
return_state <= wait_for_command;
|
394 |
|
|
|
395 |
|
|
-- --
|
396 |
|
|
-- Provide E strobing for data transfer.
|
397 |
|
|
-- Writes data byte to the LCD.
|
398 |
|
|
-- Please note, DATA and RS are set by the caller!
|
399 |
|
|
when pulse_e =>
|
400 |
|
|
-- wait 60 ns before E -> 1 (tAS)
|
401 |
|
|
delay_counter <= delay_tas;
|
402 |
|
|
current_state <= pulse_e_1;
|
403 |
|
|
when pulse_e_1 =>
|
404 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
405 |
|
|
-- timer set: E = 1 for 500 ns (PWeh)
|
406 |
|
|
delay_counter <= delay_pweh;
|
407 |
|
|
current_state <= pulse_e_2;
|
408 |
|
|
else
|
409 |
|
|
delay_counter <= delay_counter-1;
|
410 |
|
|
end if;
|
411 |
|
|
when pulse_e_2 =>
|
412 |
|
|
LCD_E <= '1';
|
413 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
414 |
|
|
-- timer set: E = 0 for 500 ns (tCycleE-PWeh)
|
415 |
|
|
delay_counter <= delay_pwel;
|
416 |
|
|
current_state <= pulse_e_3;
|
417 |
|
|
else
|
418 |
|
|
delay_counter <= delay_counter-1;
|
419 |
|
|
end if;
|
420 |
|
|
when pulse_e_3 =>
|
421 |
|
|
LCD_E <= '0';
|
422 |
|
|
-- Command completion, check for use busy flag
|
423 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
424 |
|
|
-- If no busy flag used, wait for a amount of time.
|
425 |
|
|
if use_bf_int = '0' then
|
426 |
|
|
delay_counter <= delay_no_bf;
|
427 |
|
|
current_state <= pulse_e_4;
|
428 |
|
|
else -- BF used
|
429 |
|
|
current_state <= pulse_busy_flag;
|
430 |
|
|
end if;
|
431 |
|
|
else
|
432 |
|
|
delay_counter <= delay_counter-1;
|
433 |
|
|
end if;
|
434 |
|
|
when pulse_e_4 =>
|
435 |
|
|
-- Wait for the delay to finsh and then return to the caller.
|
436 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
437 |
|
|
current_state <= return_state;
|
438 |
|
|
else
|
439 |
|
|
delay_counter <= delay_counter-1;
|
440 |
|
|
end if;
|
441 |
|
|
|
442 |
|
|
-- Let's read the busy flag, see if the module is busy...
|
443 |
|
|
when pulse_busy_flag =>
|
444 |
|
|
LCD_DB <= (others => 'Z');
|
445 |
|
|
LCD_RW <= '1';
|
446 |
|
|
LCD_RS <= '0';
|
447 |
|
|
-- wait 60 ns before E -> 1 (tAS)
|
448 |
|
|
delay_counter <= delay_tas;
|
449 |
|
|
current_state <= pulse_busy_flag_1;
|
450 |
|
|
when pulse_busy_flag_1 =>
|
451 |
|
|
LCD_RW <= '1';
|
452 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
453 |
|
|
-- timer set: E = 1 for 500 ns (tPWeh)
|
454 |
|
|
delay_counter <= delay_pweh;
|
455 |
|
|
current_state <= pulse_busy_flag_2;
|
456 |
|
|
else
|
457 |
|
|
delay_counter <= delay_counter-1;
|
458 |
|
|
end if;
|
459 |
|
|
when pulse_busy_flag_2 =>
|
460 |
|
|
LCD_E <= '1';
|
461 |
|
|
LCD_RW <= '1';
|
462 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
463 |
|
|
-- timer set: E = 0 for 500 ns (tPWel)
|
464 |
|
|
delay_counter <= delay_pwel;
|
465 |
|
|
current_state <= pulse_busy_flag_3;
|
466 |
|
|
else
|
467 |
|
|
delay_counter <= delay_counter-1;
|
468 |
|
|
end if;
|
469 |
|
|
when pulse_busy_flag_3 =>
|
470 |
|
|
LCD_E <= '0';
|
471 |
|
|
LCD_RW <= '1';
|
472 |
|
|
if LCD_DB(7) = '0' then
|
473 |
|
|
-- operation ended
|
474 |
|
|
current_state <= pulse_busy_flag_4;
|
475 |
|
|
else
|
476 |
|
|
-- operation in progress
|
477 |
|
|
current_state <= pulse_busy_flag_5;
|
478 |
|
|
end if;
|
479 |
|
|
when pulse_busy_flag_4 =>
|
480 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
481 |
|
|
-- Operation ended, return caller
|
482 |
|
|
current_state <= return_state;
|
483 |
|
|
else
|
484 |
|
|
delay_counter <= delay_counter-1;
|
485 |
|
|
end if;
|
486 |
|
|
when pulse_busy_flag_5 =>
|
487 |
|
|
if delay_counter = 0 or delay_counter = 1 then
|
488 |
|
|
-- Operation in progress, read BF again
|
489 |
|
|
current_state <= pulse_busy_flag;
|
490 |
|
|
else
|
491 |
|
|
delay_counter <= delay_counter-1;
|
492 |
|
|
end if;
|
493 |
|
|
|
494 |
|
|
when others => null;
|
495 |
|
|
end case;
|
496 |
|
|
end if;
|
497 |
|
|
|
498 |
|
|
end process;
|
499 |
|
|
|
500 |
|
|
end architecture hardware_driver;
|