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