This repository has been archived by the owner on Jul 17, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLCD_Display.vhd
241 lines (234 loc) · 8.84 KB
/
LCD_Display.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.all;
USE IEEE.STD_LOGIC_UNSIGNED.all;
-- SW8 (GLOBAL RESET) resets LCD
ENTITY LCD_Display IS
-- Enter number of live Hex hardware data values to display
-- (do not count ASCII character constants)
GENERIC(NumHexDig: Integer:= 11);
-----------------------------------------------------------------------
-- LCD Displays 16 Characters on 2 lines
-- LCD_display string is an ASCII character string entered in hex for
-- the two lines of the LCD Display (See ASCII to hex table below)
-- Edit LCD_Display_String entries above to modify display
-- Enter the ASCII character's 2 hex digit equivalent value
-- (see table below for ASCII hex values)
-- To display character assign ASCII value to LCD_display_string(x)
-- To skip a character use X"20" (ASCII space)
-- To dislay "live" hex values from hardware on LCD use the following:
-- make array element for that character location X"0" & 4-bit field from HexDisplayData
-- state machine sees X"0" in high 4-bits & grabs the next lower 4-bits from HexDisplayData input
-- and performs 4-bit binary to ASCII conversion needed to print a hex digit
-- Num_Hex_Digits must be set to the count of hex data characters (ie. "00"s) in the display
-- Connect hardware bits to display to HexDisplayData input
-- To display less than 32 characters, terminate string with an entry of X"FE"
-- (fewer characters may slightly increase the LCD's data update rate)
-------------------------------------------------------------------
-- ASCII HEX TABLE
-- Hex Low Hex Digit
-- Value 0 1 2 3 4 5 6 7 8 9 A B C D E F
------\----------------------------------------------------------------
--H 2 | SP ! " # $ % & ' ( ) * + , - . /
--i 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
--g 4 | @ A B C D E F G H I J K L M N O
--h 5 | P Q R S T U V W X Y Z [ \ ] ^ _
-- 6 | ` a b c d e f g h i j k l m n o
-- 7 | p q r s t u v w x y z { | } ~ DEL
-----------------------------------------------------------------------
-- Example "A" is row 4 column 1, so hex value is X"41"
-- *see LCD Controller's Datasheet for other graphics characters available
--
PORT(reset, clk_48Mhz : IN STD_LOGIC;
LCD_RS, LCD_E : OUT STD_LOGIC;
LCD_RW : OUT STD_LOGIC;
DATA_BUS : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
Linha1 : IN STD_LOGIC_VECTOR(127 DOWNTO 0);
Linha2 : IN STD_LOGIC_VECTOR(127 DOWNTO 0));
END ENTITY LCD_Display;
ARCHITECTURE a OF LCD_Display IS
TYPE character_string IS ARRAY ( 0 TO 31 ) OF STD_LOGIC_VECTOR( 7 DOWNTO 0 );
TYPE STATE_TYPE IS (HOLD, FUNC_SET, DISPLAY_ON, MODE_SET, Print_String,
LINE2, RETURN_HOME, DROP_LCD_E, RESET1, RESET2,
RESET3, DISPLAY_OFF, DISPLAY_CLEAR);
SIGNAL state, next_command: STATE_TYPE;
SIGNAL LCD_display_string : character_string;
-- Enter new ASCII hex data above for LCD Display
SIGNAL DATA_BUS_VALUE, Next_Char: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL CLK_COUNT_400HZ: STD_LOGIC_VECTOR(19 DOWNTO 0);
SIGNAL CHAR_COUNT: STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL CLK_400HZ_Enable,LCD_RW_INT : STD_LOGIC;
SIGNAL Line1_chars, Line2_chars: STD_LOGIC_VECTOR(127 DOWNTO 0);
BEGIN
Line1_chars <= Linha1;
Line2_chars <= Linha2;
LCD_display_string <= (
-- Line 1
Line1_chars(127 DOWNTO 120), Line1_chars(119 DOWNTO 112), Line1_chars(111 DOWNTO 104), Line1_chars(103 DOWNTO 96), Line1_chars(95 DOWNTO 88),
Line1_chars(87 DOWNTO 80), Line1_chars(79 DOWNTO 72), Line1_chars(71 DOWNTO 64), Line1_chars(63 DOWNTO 56), Line1_chars(55 DOWNTO 48),
Line1_chars(47 DOWNTO 40), Line1_chars(39 DOWNTO 32), Line1_chars(31 DOWNTO 24), Line1_chars(23 DOWNTO 16), Line1_chars(15 DOWNTO 8),
Line1_chars(7 DOWNTO 0),
-- Line 2
Line2_chars(127 DOWNTO 120), Line2_chars(119 DOWNTO 112), Line2_chars(111 DOWNTO 104), Line2_chars(103 DOWNTO 96), Line2_chars(95 DOWNTO 88),
Line2_chars(87 DOWNTO 80), Line2_chars(79 DOWNTO 72), Line2_chars(71 DOWNTO 64), Line2_chars(63 DOWNTO 56), Line2_chars(55 DOWNTO 48),
Line2_chars(47 DOWNTO 40), Line2_chars(39 DOWNTO 32), Line2_chars(31 DOWNTO 24), Line2_chars(23 DOWNTO 16), Line2_chars(15 DOWNTO 8),
Line2_chars(7 DOWNTO 0));
-- BIDIRECTIONAL TRI STATE LCD DATA BUS
DATA_BUS <= DATA_BUS_VALUE WHEN LCD_RW_INT = '0' ELSE "ZZZZZZZZ";
-- get next character in display string
Next_Char <= LCD_display_string(CONV_INTEGER(CHAR_COUNT));
LCD_RW <= LCD_RW_INT;
PROCESS
BEGIN
WAIT UNTIL CLK_48MHZ'EVENT AND CLK_48MHZ = '1';
IF RESET = '1' THEN
CLK_COUNT_400HZ <= X"00000";
CLK_400HZ_Enable <= '0';
ELSE
IF CLK_COUNT_400HZ < X"0EA60" THEN
CLK_COUNT_400HZ <= CLK_COUNT_400HZ + 1;
CLK_400HZ_Enable <='0';
ELSE
CLK_COUNT_400HZ <= X"00000";
CLK_400HZ_Enable <= '1';
END IF;
END IF;
END PROCESS;
PROCESS
BEGIN
WAIT UNTIL CLK_48MHZ'EVENT AND CLK_48MHZ = '1';
IF reset = '1' THEN
state <= RESET1;
DATA_BUS_VALUE <= X"38";
next_command <= RESET2;
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '1';
ELSE
IF CLK_400HZ_Enable = '1' THEN
-- State Machine to send commands and data to LCD DISPLAY
CASE state IS
-- Set Function to 8-bit transfer and 2 line display with 5x8 Font size
-- see Hitachi HD44780 family data sheet for LCD command and timing details
WHEN RESET1 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= RESET2;
CHAR_COUNT <= "00000";
WHEN RESET2 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= RESET3;
WHEN RESET3 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= FUNC_SET;
-- EXTRA STATES ABOVE ARE NEEDED FOR RELIABLE PUSHBUTTON RESET OF LCD
WHEN FUNC_SET =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"38";
state <= DROP_LCD_E;
next_command <= DISPLAY_OFF;
-- Turn off Display and Turn off cursor
WHEN DISPLAY_OFF =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"08";
state <= DROP_LCD_E;
next_command <= DISPLAY_CLEAR;
-- Clear Display and Turn off cursor
WHEN DISPLAY_CLEAR =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"01";
state <= DROP_LCD_E;
next_command <= DISPLAY_ON;
-- Turn on Display and Turn off cursor
WHEN DISPLAY_ON =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"0C";
state <= DROP_LCD_E;
next_command <= MODE_SET;
-- Set write mode to auto increment address and move cursor to the right
WHEN MODE_SET =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"06";
state <= DROP_LCD_E;
next_command <= Print_String;
-- Write ASCII hex character in first LCD character location
WHEN Print_String =>
state <= DROP_LCD_E;
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW_INT <= '0';
-- ASCII character to output
IF Next_Char(7 DOWNTO 4) /= X"0" THEN
DATA_BUS_VALUE <= Next_Char;
ELSE
-- Convert 4-bit value to an ASCII hex digit
IF Next_Char(3 DOWNTO 0) >9 THEN
-- ASCII A...F
DATA_BUS_VALUE <= X"4" & (Next_Char(3 DOWNTO 0)-9);
ELSE
-- ASCII 0...9
DATA_BUS_VALUE <= X"3" & Next_Char(3 DOWNTO 0);
END IF;
END IF;
-- Loop to send out 32 characters to LCD Display (16 by 2 lines)
IF (CHAR_COUNT < 31) AND (Next_Char /= X"FE") THEN
CHAR_COUNT <= CHAR_COUNT + 1;
ELSE
CHAR_COUNT <= "00000";
END IF;
-- Jump to second line?
IF CHAR_COUNT = 15 THEN next_command <= line2;
-- Return to first line?
ELSIF (CHAR_COUNT = 31) OR (Next_Char = X"FE") THEN
next_command <= return_home;
ELSE next_command <= Print_String; END IF;
-- Set write address to line 2 character 1
WHEN LINE2 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"C0";
state <= DROP_LCD_E;
next_command <= Print_String;
-- Return write address to first character postion on line 1
WHEN RETURN_HOME =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW_INT <= '0';
DATA_BUS_VALUE <= X"80";
state <= DROP_LCD_E;
next_command <= Print_String;
-- The next three states occur at the end of each command or data transfer to the LCD
-- Drop LCD E line - falling edge loads inst/data to LCD controller
WHEN DROP_LCD_E =>
LCD_E <= '0';
state <= HOLD;
-- Hold LCD inst/data valid after falling edge of E line
WHEN HOLD =>
state <= next_command;
END CASE;
END IF;
END IF;
END PROCESS;
END a;