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