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