lcd.c


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