-
Notifications
You must be signed in to change notification settings - Fork 0
/
lcd.c
338 lines (305 loc) · 8.01 KB
/
lcd.c
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/*
* LCD Driver for EA DIPS082 / EA DOGM163W-A - PIC32
*
* Copyright 2011: Kilpatrick Audio
* Writeen by: Andrew Kilpatrick
*
* Hardware I/O:
*
* // 4 bit mode:
* // RD0 - LCD D0 - output
* // RD1 - LCD D1 - output
* // RD2 - LCD D2 - output
* // RD3 - LCD D3 - output
* // RD4 - LCD E - output
* // RD5 - LCD R/!W - output
* // RD6 - LCD RS - output
*
* SPI mode:
* RE7 - LCD serial RS - output
* RG6 - LCD SPI clock - SPI2 clock
* RG7 - LCD SPI MISO - SPI2 MISO (unused)
* RG8 - LCD SPI MOSI - SPI2 MOSI
* RG9 - LCD SPI /SS - SPI2 /SS
*
*/
#include <plib.h>
#include "TimeDelay.h"
#include "lcd.h"
// LCD panel selection
//#define LCD_4BIT
#define LCD_SPI
#define LCD_16X3
//#define LCD_8X2
// hardware defines
#define LCD_PORT LATD
#define LCD_E LATDbits.LATD4
#define LCD_RW LATDbits.LATD5
#define LCD_RS LATDbits.LATD6
#define LCD_SRS LATEbits.LATE7
#define LCD_SS LATGbits.LATG9
// commands
#define LCD_CLEAR_SCREEN 0x80
#define LCD_GOTO_XY 0x81
#define LCD_SHIFT_LEFT 0x82
#define LCD_SHIFT_RIGHT 0x83
#define LCD_CONTRAST 0x84
// control state machine
#define CMD_MODE_NORMAL 0
#define CMD_MODE_XY_X 1
#define CMD_MODE_XY_Y 2
#define CMD_MODE_CONTRAST 3
unsigned char cmd_mode;
unsigned char temp_x;
unsigned char temp_y;
unsigned char contrast;
// local functions
void lcd_write_cmd(unsigned char spi, unsigned char cmd);
void lcd_write_data(unsigned char spi, unsigned char data);
void lcd_write(unsigned char spi, unsigned char data);
unsigned char cmd_buf[256];
unsigned char cmd_buf_in;
unsigned char cmd_buf_out;
// initialize the display
void lcd_init(void) {
DelayMs(100);
cmd_buf_in = 0;
cmd_buf_out = 0;
cmd_mode = CMD_MODE_NORMAL;
contrast = 0x0e;
#ifdef LCD_4BIT
// LCD pins
PORTSetPinsDigitalOut(IOPORT_D, BIT_0 | BIT_1 | BIT_2 | \
BIT_3 | BIT_4 | BIT_5 | BIT_6);
LCD_E = 0;
LCD_RW = 0;
// init 4 bit mode
lcd_write_cmd(0, 0x33);
lcd_write_cmd(0, 0x32);
lcd_write_cmd(0, 0x29);
// init the display
lcd_write_cmd(0, 0x15); // bias set - fixed on high
lcd_write_cmd(0, 0x53); // power control - internal follower
lcd_write_cmd(0, 0x6c); // follower control - on, rab2
lcd_write_cmd(0, 0x7f); // contrast set
lcd_write_cmd(0, 0x28); // instruction set 0 - 4 bit, 2 line, normal instruction
lcd_write_cmd(0, 0x0c); // display on - display on, cursor off, blink off
// lcd_write_cmd(0, 0x0f); // display on - display on, cursor on, blink on
lcd_write_cmd(0, 0x01); // clear display
DelayMs(2);
lcd_write_cmd(0, 0x06); // entry mode - increment on, shift off
#endif
#ifdef LCD_SPI
PORTSetPinsDigitalOut(IOPORT_E, BIT_7);
PORTSetPinsDigitalOut(IOPORT_G, BIT_9);
LCD_SRS = 1;
LCD_SS = 1;
SpiChnOpen(SPI_CHANNEL2, SPI_OPEN_MSTEN | SPI_OPEN_SMP_END | SPI_OPEN_MODE8, 32);
DelayMs(2);
lcd_write_cmd(1, 0x38); // function set
lcd_write_cmd(1, 0x39); // function set
lcd_write_cmd(1, 0x15); // bias set - 1/5, 3 line LCD
lcd_write_cmd(1, 0x7e); // contrast set
lcd_write_cmd(1, 0x54); // power control - booster on, contrast C5, set C4
lcd_write_cmd(1, 0x6e); // follower control - set voltage follower and gain
DelayMs(250);
lcd_write_cmd(1, 0x38); // instruction set 0
lcd_write_cmd(1, 0x0c); // display on - display on, cursor off, blink off
// lcd_write_cmd(1, 0x0f); // display on - display on, cursor on, blink on
lcd_write_cmd(1, 0x01); // clear display
DelayMs(2);
lcd_write_cmd(1, 0x06); // entry mode - increment on, shift off
#endif
}
// handle LCD writes
void lcd_task(void) {
unsigned char cmd;
if(cmd_buf_in == cmd_buf_out) return;
// get a new command
INTDisableInterrupts();
cmd = cmd_buf[cmd_buf_out];
cmd_buf_out ++;
INTEnableInterrupts();
// handle multi-byte commands
if(cmd_mode == CMD_MODE_XY_X) {
temp_x = cmd;
cmd_mode = CMD_MODE_XY_Y;
return;
}
if(cmd_mode == CMD_MODE_XY_Y) {
temp_y = cmd;
#ifdef LCD_SPI
#ifdef LCD_16X3
lcd_write_cmd(1, 0x80 | ((temp_y & 0x03) << 4) | (temp_x & 0x04));
#elif LCD_8x2
lcd_write_cmd(1, 0x80 | ((temp_y & 0x01) << 6) | (temp_x & 0x03));
#endif
#endif
#ifdef LCD_4BIT
#ifdef LCD_16X3
lcd_write_cmd(0, 0x80 | ((temp_y & 0x03) << 4) | (temp_x & 0x04));
#elif LCD_8X2
lcd_write_cmd(0, 0x80 | ((temp_y & 0x01) << 6) | (temp_x & 0x03));
#endif
#endif
cmd_mode = CMD_MODE_NORMAL;
return;
}
if(cmd_mode == CMD_MODE_CONTRAST) {
#ifdef LCD_SPI
lcd_write_cmd(1, 0x21); // instruction table 1
lcd_write_cmd(1, 0x54 | ((cmd & 0x30) >> 4));
lcd_write_cmd(1, 0x70 | (cmd & 0x0f));
lcd_write_cmd(1, 0x20); // instruction table 0
#endif
#ifdef LCD_4BIT
lcd_write_cmd(0, 0x0c); // display on - display on, cursor off, blink off
lcd_write_cmd(0, 0x54 | ((cmd & 0x30) >> 4));
lcd_write_cmd(0, 0x70 | (cmd & 0x0f));
lcd_write_cmd(0, 0x0c); // instruction table 0
#endif
cmd_mode = CMD_MODE_NORMAL;
return;
}
// commands
if(cmd & 0x80) {
if(cmd == LCD_CLEAR_SCREEN) {
#ifdef LCD_SPI
lcd_write_cmd(1, 0x01); // clear display
DelayMs(2);
lcd_write_cmd(1, 0x02); // return home
DelayMs(2);
#endif
#ifdef LCD_4BIT
lcd_write_cmd(0, 0x01); // clear display
DelayMs(2);
lcd_write_cmd(0, 0x02); // return home
DelayMs(2);
#endif
}
else if(cmd == LCD_GOTO_XY) {
cmd_mode = CMD_MODE_XY_X;
}
else if(cmd == LCD_CONTRAST) {
cmd_mode = CMD_MODE_CONTRAST;
}
else if(cmd == LCD_SHIFT_LEFT) {
#ifdef LCD_SPI
lcd_write_cmd(1, 0x18);
#endif
#ifdef LCD_4BIT
lcd_write_cmd(0, 0x18);
#endif
}
else if(cmd == LCD_SHIFT_RIGHT) {
#ifdef LCD_SPI
lcd_write_cmd(1, 0x1c);
#endif
#ifdef LCD_4BIT
lcd_write_cmd(0, 0x1c);
#endif
}
}
// print data
else {
#ifdef LCD_SPI
lcd_write_data(1, cmd);
#endif
#ifdef LCD_4BIT
lcd_write_data(0, cmd);
#endif
}
}
// clear the screen
void lcd_clear_screen(void) {
cmd_buf[cmd_buf_in] = LCD_CLEAR_SCREEN;
cmd_buf_in ++;
}
// go to X / Y position
void lcd_goto_xy(unsigned char x, unsigned char y) {
cmd_buf[cmd_buf_in] = LCD_GOTO_XY;
cmd_buf_in ++;
cmd_buf[cmd_buf_in] = (x & 0x7f);
cmd_buf_in ++;
cmd_buf[cmd_buf_in] = (y & 0x7f);
cmd_buf_in ++;
}
// shift the display to the left
void lcd_shift_left(void) {
cmd_buf[cmd_buf_in] = LCD_SHIFT_LEFT;
cmd_buf_in ++;
}
// shift the display to the right
void lcd_shift_right(void) {
cmd_buf[cmd_buf_in] = LCD_SHIFT_RIGHT;
cmd_buf_in ++;
}
// print a string at the current position
void lcd_print_str(char *str) {
while(*str) {
cmd_buf[cmd_buf_in] = *str;
cmd_buf_in ++;
*str++;
}
}
// print a character at the current position
void lcd_print_char(char ch) {
cmd_buf[cmd_buf_in] = ch;
cmd_buf_in ++;
}
// get the contrast
unsigned char lcd_get_contrast(void) {
return contrast;
}
// set the contrast - for digitally controlled contrast only
void lcd_set_contrast(unsigned char cont) {
contrast = cont;
cmd_buf[cmd_buf_in] = LCD_CONTRAST;
cmd_buf_in ++;
cmd_buf[cmd_buf_in] = (contrast >> 4) + 6;;
cmd_buf_in ++;
}
//
// HARDWARE CONTROL
//
// write a command to the display
void lcd_write_cmd(unsigned char spi, unsigned char cmd) {
if(spi) LCD_SRS = 0;
else LCD_RS = 0;
lcd_write(spi, cmd);
}
// write data to the display
void lcd_write_data(unsigned char spi, unsigned char data) {
if(spi) LCD_SRS = 1;
else LCD_RS = 1;
lcd_write(spi, data);
}
// write to the display
void lcd_write(unsigned char spi, unsigned char data) {
if(spi) {
LCD_SS = 0;
SpiChnPutC(SPI_CHANNEL2, data);
while(SpiChnIsBusy(SPI_CHANNEL2)) ClearWDT();
Delay10us(1);
LCD_SS = 1;
}
else {
// high nibble
unsigned char nibble = (data & 0xf0) >> 4;
LCD_PORT &= 0xfff0;
LCD_PORT |= nibble;
Delay10us(1);
LCD_E = 1;
Delay10us(1);
LCD_E = 0;
// low nibble
nibble = data & 0x0f;
LCD_PORT &= 0xfff0;
LCD_PORT |= nibble;
Delay10us(1);
LCD_E = 1;
Delay10us(1);
LCD_E = 0;
}
Delay10us(3);
}