aboutsummaryrefslogtreecommitdiff
path: root/platforms/avr/drivers/hd44780.c
diff options
context:
space:
mode:
Diffstat (limited to 'platforms/avr/drivers/hd44780.c')
-rw-r--r--platforms/avr/drivers/hd44780.c536
1 files changed, 536 insertions, 0 deletions
diff --git a/platforms/avr/drivers/hd44780.c b/platforms/avr/drivers/hd44780.c
new file mode 100644
index 000000000..f71069dec
--- /dev/null
+++ b/platforms/avr/drivers/hd44780.c
@@ -0,0 +1,536 @@
1/****************************************************************************
2 Title: HD44780U LCD library
3 Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury
4 License: GNU General Public License Version 3
5 File: $Id: lcd.c,v 1.15.2.2 2015/01/17 12:16:05 peter Exp $
6 Software: AVR-GCC 3.3
7 Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega
8
9 DESCRIPTION
10 Basic routines for interfacing a HD44780U-based text lcd display
11
12 Originally based on Volker Oth's lcd library,
13 changed lcd_init(), added additional constants for lcd_command(),
14 added 4-bit I/O mode, improved and optimized code.
15
16 Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in
17 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.
18
19 Memory mapped mode compatible with Kanda STK200, but supports also
20 generation of R/W signal through A8 address line.
21
22 USAGE
23 See the C include lcd.h file for a description of each function
24
25*****************************************************************************/
26#include <inttypes.h>
27#include <avr/io.h>
28#include <avr/pgmspace.h>
29#include <util/delay.h>
30#include "hd44780.h"
31
32/*
33** constants/macros
34*/
35#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */
36#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
37/* on ATmega64/128 PINF is on port 0x00 and not 0x60 */
38# define PIN(x) (&PORTF == &(x) ? _SFR_IO8(0x00) : (*(&x - 2)))
39#else
40# define PIN(x) (*(&x - 2)) /* address of input register of port x */
41#endif
42
43#if LCD_IO_MODE
44# define lcd_e_delay() _delay_us(LCD_DELAY_ENABLE_PULSE)
45# define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN);
46# define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN);
47# define lcd_e_toggle() toggle_e()
48# define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN)
49# define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN)
50# define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN)
51# define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN)
52#endif
53
54#if LCD_IO_MODE
55# if LCD_LINES == 1
56# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
57# else
58# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
59# endif
60#else
61# if LCD_LINES == 1
62# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE
63# else
64# define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES
65# endif
66#endif
67
68#if LCD_CONTROLLER_KS0073
69# if LCD_LINES == 4
70
71# define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x2C /* |0|010|1100 4-bit mode, extension-bit RE = 1 */
72# define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x28 /* |0|010|1000 4-bit mode, extension-bit RE = 0 */
73# define KS0073_4LINES_MODE 0x09 /* |0|000|1001 4 lines mode */
74
75# endif
76#endif
77
78/*
79** function prototypes
80*/
81#if LCD_IO_MODE
82static void toggle_e(void);
83#endif
84
85/*
86** local functions
87*/
88
89/*************************************************************************
90delay for a minimum of <us> microseconds
91the number of loops is calculated at compile-time from MCU clock frequency
92*************************************************************************/
93#define delay(us) _delay_us(us)
94
95#if LCD_IO_MODE
96/* toggle Enable Pin to initiate write */
97static void toggle_e(void) {
98 lcd_e_high();
99 lcd_e_delay();
100 lcd_e_low();
101}
102#endif
103
104/*************************************************************************
105Low-level function to write byte to LCD controller
106Input: data byte to write to LCD
107 rs 1: write data
108 0: write instruction
109Returns: none
110*************************************************************************/
111#if LCD_IO_MODE
112static void lcd_write(uint8_t data, uint8_t rs) {
113 unsigned char dataBits;
114
115 if (rs) { /* write data (RS=1, RW=0) */
116 lcd_rs_high();
117 } else { /* write instruction (RS=0, RW=0) */
118 lcd_rs_low();
119 }
120 lcd_rw_low(); /* RW=0 write mode */
121
122 if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)) {
123 /* configure data pins as output */
124 DDR(LCD_DATA0_PORT) |= 0x0F;
125
126 /* output high nibble first */
127 dataBits = LCD_DATA0_PORT & 0xF0;
128 LCD_DATA0_PORT = dataBits | ((data >> 4) & 0x0F);
129 lcd_e_toggle();
130
131 /* output low nibble */
132 LCD_DATA0_PORT = dataBits | (data & 0x0F);
133 lcd_e_toggle();
134
135 /* all data pins high (inactive) */
136 LCD_DATA0_PORT = dataBits | 0x0F;
137 } else {
138 /* configure data pins as output */
139 DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
140 DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
141 DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
142 DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
143
144 /* output high nibble first */
145 LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
146 LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
147 LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
148 LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
149 if (data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
150 if (data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
151 if (data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
152 if (data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
153 lcd_e_toggle();
154
155 /* output low nibble */
156 LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
157 LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
158 LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
159 LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
160 if (data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
161 if (data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
162 if (data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
163 if (data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
164 lcd_e_toggle();
165
166 /* all data pins high (inactive) */
167 LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
168 LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
169 LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
170 LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
171 }
172}
173#else
174# define lcd_write(d, rs) \
175 if (rs) \
176 *(volatile uint8_t *)(LCD_IO_DATA) = d; \
177 else \
178 *(volatile uint8_t *)(LCD_IO_FUNCTION) = d;
179/* rs==0 -> write instruction to LCD_IO_FUNCTION */
180/* rs==1 -> write data to LCD_IO_DATA */
181#endif
182
183/*************************************************************************
184Low-level function to read byte from LCD controller
185Input: rs 1: read data
186 0: read busy flag / address counter
187Returns: byte read from LCD controller
188*************************************************************************/
189#if LCD_IO_MODE
190static uint8_t lcd_read(uint8_t rs) {
191 uint8_t data;
192
193 if (rs)
194 lcd_rs_high(); /* RS=1: read data */
195 else
196 lcd_rs_low(); /* RS=0: read busy flag */
197 lcd_rw_high(); /* RW=1 read mode */
198
199 if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)) {
200 DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */
201
202 lcd_e_high();
203 lcd_e_delay();
204 data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */
205 lcd_e_low();
206
207 lcd_e_delay(); /* Enable 500ns low */
208
209 lcd_e_high();
210 lcd_e_delay();
211 data |= PIN(LCD_DATA0_PORT) & 0x0F; /* read low nibble */
212 lcd_e_low();
213 } else {
214 /* configure data pins as input */
215 DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);
216 DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);
217 DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);
218 DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);
219
220 /* read high nibble first */
221 lcd_e_high();
222 lcd_e_delay();
223 data = 0;
224 if (PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN)) data |= 0x10;
225 if (PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN)) data |= 0x20;
226 if (PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN)) data |= 0x40;
227 if (PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN)) data |= 0x80;
228 lcd_e_low();
229
230 lcd_e_delay(); /* Enable 500ns low */
231
232 /* read low nibble */
233 lcd_e_high();
234 lcd_e_delay();
235 if (PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN)) data |= 0x01;
236 if (PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN)) data |= 0x02;
237 if (PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN)) data |= 0x04;
238 if (PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN)) data |= 0x08;
239 lcd_e_low();
240 }
241 return data;
242}
243#else
244# define lcd_read(rs) (rs) ? *(volatile uint8_t *)(LCD_IO_DATA + LCD_IO_READ) : *(volatile uint8_t *)(LCD_IO_FUNCTION + LCD_IO_READ)
245/* rs==0 -> read instruction from LCD_IO_FUNCTION */
246/* rs==1 -> read data from LCD_IO_DATA */
247#endif
248
249/*************************************************************************
250loops while lcd is busy, returns address counter
251*************************************************************************/
252static uint8_t lcd_waitbusy(void)
253
254{
255 register uint8_t c;
256
257 /* wait until busy flag is cleared */
258 while ((c = lcd_read(0)) & (1 << LCD_BUSY)) {
259 }
260
261 /* the address counter is updated 4us after the busy flag is cleared */
262 delay(LCD_DELAY_BUSY_FLAG);
263
264 /* now read the address counter */
265 return (lcd_read(0)); // return address counter
266
267} /* lcd_waitbusy */
268
269/*************************************************************************
270Move cursor to the start of next line or to the first line if the cursor
271is already on the last line.
272*************************************************************************/
273static inline void lcd_newline(uint8_t pos) {
274 register uint8_t addressCounter;
275
276#if LCD_LINES == 1
277 addressCounter = 0;
278#endif
279#if LCD_LINES == 2
280 if (pos < (LCD_START_LINE2))
281 addressCounter = LCD_START_LINE2;
282 else
283 addressCounter = LCD_START_LINE1;
284#endif
285#if LCD_LINES == 4
286# if KS0073_4LINES_MODE
287 if (pos < LCD_START_LINE2)
288 addressCounter = LCD_START_LINE2;
289 else if ((pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3))
290 addressCounter = LCD_START_LINE3;
291 else if ((pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4))
292 addressCounter = LCD_START_LINE4;
293 else
294 addressCounter = LCD_START_LINE1;
295# else
296 if (pos < LCD_START_LINE3)
297 addressCounter = LCD_START_LINE2;
298 else if ((pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4))
299 addressCounter = LCD_START_LINE3;
300 else if ((pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2))
301 addressCounter = LCD_START_LINE4;
302 else
303 addressCounter = LCD_START_LINE1;
304# endif
305#endif
306 lcd_command((1 << LCD_DDRAM) + addressCounter);
307
308} /* lcd_newline */
309
310/*
311** PUBLIC FUNCTIONS
312*/
313
314/*************************************************************************
315Send LCD controller instruction command
316Input: instruction to send to LCD controller, see HD44780 data sheet
317Returns: none
318*************************************************************************/
319void lcd_command(uint8_t cmd) {
320 lcd_waitbusy();
321 lcd_write(cmd, 0);
322}
323
324/*************************************************************************
325Send data byte to LCD controller
326Input: data to send to LCD controller, see HD44780 data sheet
327Returns: none
328*************************************************************************/
329void lcd_data(uint8_t data) {
330 lcd_waitbusy();
331 lcd_write(data, 1);
332}
333
334/*************************************************************************
335Set cursor to specified position
336Input: x horizontal position (0: left most position)
337 y vertical position (0: first line)
338Returns: none
339*************************************************************************/
340void lcd_gotoxy(uint8_t x, uint8_t y) {
341#if LCD_LINES == 1
342 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
343#endif
344#if LCD_LINES == 2
345 if (y == 0)
346 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
347 else
348 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
349#endif
350#if LCD_LINES == 4
351 if (y == 0)
352 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
353 else if (y == 1)
354 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
355 else if (y == 2)
356 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
357 else /* y==3 */
358 lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x);
359#endif
360
361} /* lcd_gotoxy */
362
363/*************************************************************************
364*************************************************************************/
365int lcd_getxy(void) { return lcd_waitbusy(); }
366
367/*************************************************************************
368Clear display and set cursor to home position
369*************************************************************************/
370void lcd_clrscr(void) { lcd_command(1 << LCD_CLR); }
371
372/*************************************************************************
373Set cursor to home position
374*************************************************************************/
375void lcd_home(void) { lcd_command(1 << LCD_HOME); }
376
377/*************************************************************************
378Display character at current cursor position
379Input: character to be displayed
380Returns: none
381*************************************************************************/
382void lcd_putc(char c) {
383 uint8_t pos;
384
385 pos = lcd_waitbusy(); // read busy-flag and address counter
386 if (c == '\n') {
387 lcd_newline(pos);
388 } else {
389#if LCD_WRAP_LINES == 1
390# if LCD_LINES == 1
391 if (pos == LCD_START_LINE1 + LCD_DISP_LENGTH) {
392 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1, 0);
393 }
394# elif LCD_LINES == 2
395 if (pos == LCD_START_LINE1 + LCD_DISP_LENGTH) {
396 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2, 0);
397 } else if (pos == LCD_START_LINE2 + LCD_DISP_LENGTH) {
398 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1, 0);
399 }
400# elif LCD_LINES == 4
401 if (pos == LCD_START_LINE1 + LCD_DISP_LENGTH) {
402 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE2, 0);
403 } else if (pos == LCD_START_LINE2 + LCD_DISP_LENGTH) {
404 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE3, 0);
405 } else if (pos == LCD_START_LINE3 + LCD_DISP_LENGTH) {
406 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE4, 0);
407 } else if (pos == LCD_START_LINE4 + LCD_DISP_LENGTH) {
408 lcd_write((1 << LCD_DDRAM) + LCD_START_LINE1, 0);
409 }
410# endif
411 lcd_waitbusy();
412#endif
413 lcd_write(c, 1);
414 }
415
416} /* lcd_putc */
417
418/*************************************************************************
419Display string without auto linefeed
420Input: string to be displayed
421Returns: none
422*************************************************************************/
423void lcd_puts(const char *s)
424/* print string on lcd (no auto linefeed) */
425{
426 register char c;
427
428 while ((c = *s++)) {
429 lcd_putc(c);
430 }
431
432} /* lcd_puts */
433
434/*************************************************************************
435Display string from program memory without auto linefeed
436Input: string from program memory be be displayed
437Returns: none
438*************************************************************************/
439void lcd_puts_p(const char *progmem_s)
440/* print string from program memory on lcd (no auto linefeed) */
441{
442 register char c;
443
444 while ((c = pgm_read_byte(progmem_s++))) {
445 lcd_putc(c);
446 }
447
448} /* lcd_puts_p */
449
450/*************************************************************************
451Initialize display and select type of cursor
452Input: dispAttr LCD_DISP_OFF display off
453 LCD_DISP_ON display on, cursor off
454 LCD_DISP_ON_CURSOR display on, cursor on
455 LCD_DISP_CURSOR_BLINK display on, cursor on flashing
456Returns: none
457*************************************************************************/
458void lcd_init(uint8_t dispAttr) {
459#if LCD_IO_MODE
460 /*
461 * Initialize LCD to 4 bit I/O mode
462 */
463
464 if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (&LCD_RS_PORT == &LCD_DATA0_PORT) && (&LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) && (LCD_RS_PIN == 4) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6)) {
465 /* configure all port bits as output (all LCD lines on same port) */
466 DDR(LCD_DATA0_PORT) |= 0x7F;
467 } else if ((&LCD_DATA0_PORT == &LCD_DATA1_PORT) && (&LCD_DATA1_PORT == &LCD_DATA2_PORT) && (&LCD_DATA2_PORT == &LCD_DATA3_PORT) && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)) {
468 /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */
469 DDR(LCD_DATA0_PORT) |= 0x0F;
470 DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
471 DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
472 DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
473 } else {
474 /* configure all port bits as output (LCD data and control lines on different ports */
475 DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
476 DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
477 DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
478 DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
479 DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
480 DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
481 DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
482 }
483 delay(LCD_DELAY_BOOTUP); /* wait 16ms or more after power-on */
484
485 /* initial write to lcd is 8bit */
486 LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // LCD_FUNCTION>>4;
487 LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // LCD_FUNCTION_8BIT>>4;
488 lcd_e_toggle();
489 delay(LCD_DELAY_INIT); /* delay, busy flag can't be checked here */
490
491 /* repeat last command */
492 lcd_e_toggle();
493 delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */
494
495 /* repeat last command a third time */
496 lcd_e_toggle();
497 delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */
498
499 /* now configure for 4bit mode */
500 LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4
501 lcd_e_toggle();
502 delay(LCD_DELAY_INIT_4BIT); /* some displays need this additional delay */
503
504 /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */
505#else
506 /*
507 * Initialize LCD to 8 bit memory mapped mode
508 */
509
510 /* enable external SRAM (memory mapped lcd) and one wait state */
511 MCUCR = _BV(SRE) | _BV(SRW);
512
513 /* reset LCD */
514 delay(LCD_DELAY_BOOTUP); /* wait 16ms after power-on */
515 lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */
516 delay(LCD_DELAY_INIT); /* wait 5ms */
517 lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */
518 delay(LCD_DELAY_INIT_REP); /* wait 64us */
519 lcd_write(LCD_FUNCTION_8BIT_1LINE, 0); /* function set: 8bit interface */
520 delay(LCD_DELAY_INIT_REP); /* wait 64us */
521#endif
522
523#if KS0073_4LINES_MODE
524 /* Display with KS0073 controller requires special commands for enabling 4 line mode */
525 lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);
526 lcd_command(KS0073_4LINES_MODE);
527 lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);
528#else
529 lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
530#endif
531 lcd_command(LCD_DISP_OFF); /* display off */
532 lcd_clrscr(); /* display clear */
533 lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
534 lcd_command(dispAttr); /* display/cursor control */
535
536} /* lcd_init */