OSDN Git Service

[IDLE] Maybe correct time.
[openi2cradio/OpenI2CRadio.git] / lcd_acm1602.c
1 /*
2  * OpenI2CRADIO
3  * I2C/Parallel LCD ACM1602 Handler, variant of ST7066U.
4  * Copyright (C) 2013-06-10 K.Ohta <whatisthis.sowhat ai gmail.com>
5  * License: GPL2+LE
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2,
10  *  or (at your option) any later version.
11  *  This library / program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  *  See the GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this library; see the file COPYING. If not, write to the
18  *  Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  *
21  *  As a special exception, if you link this(includeed from sdcc) library
22  *  with other files, some of which are compiled with SDCC,
23  *  to produce an executable, this library does not by itself cause
24  *  the resulting executable to be covered by the GNU General Public License.
25  *  This exception does not however invalidate any other reasons why
26  *  the executable file might be covered by the GNU General Public License.
27  */
28
29 #include "iodef.h"
30 #include "lcd_acm1602.h"
31
32 #ifdef _USE_I2C_1602
33 static unsigned char lcd_busychk(addr)
34 {
35     unsigned char b, d;
36     i2c_idle();
37     OPENASMASTER();
38     i2c_writechar(addr | 0x01); // Read
39     i2c_writechar(0x00);
40     d = i2c_readchar();
41     CLOSEASMASTER();
42     _ACM1602_I2C_WAIT(); // 5.5ms
43     if((d & _LCDPORT_BUSYMASK) != 0){
44         d = 0xff; // BUSY
45     } else {
46         d = 0;
47     }
48     return d;
49 }
50
51 void lcd_waitbusy(unsigned char addr, unsigned char flag)
52 {
53     unsigned char f,ff;
54     ff = flag;
55     if(ff != 0) ff = 0xff;
56     do {
57         f = lcd_busychk(addr);
58         _ACM1602_SHORT_WAIT(); // Wait 0.1ms
59     } while(f != ff);
60 }
61
62
63 static void sendcmd(unsigned char addr, unsigned char cmd, unsigned char busyflag)
64 {
65     i2c_idle();
66     OPENASMASTER();
67     i2c_writechar(addr & 0xfe);
68     i2c_writechar(0x00);
69     i2c_writechar(cmd);
70     CLOSEASMASTER();
71     _ACM1602_I2C_WAIT(); // 5.5ms
72 }
73
74 static void sendonce(unsigned char addr, unsigned char cmd)
75 {
76     sendcmd(addr, cmd, 0x00);
77 }
78
79 static void acm1602_ioinit(unsigned char addr)
80 {
81     _ACM1602_LONG_LONG_WAIT();
82     return;
83 }
84
85 void acm1602_putchar(unsigned char addr, unsigned char c)
86 {
87     i2c_idle();
88     OPENASMASTER();
89     i2c_writechar(addr & 0xfe);
90     i2c_writechar(0x80); //Data
91     i2c_writechar(c); // Putchar
92     CLOSEASMASTER();
93     _ACM1602_I2C_WAIT(); // Wait 50us
94 }
95
96
97 unsigned char acm1602_getchar(unsigned char addr)
98 {
99     unsigned char d;
100     i2c_idle();
101     OPENASMASTER();
102     i2c_writechar(addr | 0x01); // Read
103     i2c_writechar(0x80);
104     d = i2c_readchar();
105     CLOSEASMASTER();
106     _ACM1602_I2C_WAIT(); // 5.5ms
107     return d;
108 }
109 #else // Parallel
110 static unsigned char lcd_busychk(unsigned char addr)
111 {
112     unsigned char b, d;
113
114     // Set mask for Tristate.
115     b = _LCDPORT_TRIS_DATA;
116     b |= _LCDPORT_READMASK;// Set mask for Tristate, direction = read.
117     _LCDPORT_TRIS_DATA = b;
118
119 //    b = _LCDPORT_CONT_LATCH;
120     _LCDPORT_CONT_RS = 0;
121     _LCDPORT_CONT_RW = 1;
122 //    _LCDPORT_CONT_LATCH = b;
123     _ACM1602_TC_WAIT(); // Wait 2.5?us
124
125     _LCDPORT_CONT_EN = 1; // Send CMD
126 //    _LCDPORT_CONT_LATCH = b;
127     _ACM1602_TC_WAIT(); // Wait 2.5?us
128
129     d = _LCDPORT_DATA;
130     _ACM1602_TC_WAIT(); // Wait 2.5?us
131
132     _LCDPORT_CONT_EN = 0; // Disable EN
133 //    _LCDPORT_CONT_LATCH = b;
134     _ACM1602_TC_WAIT(); // Wait 2.5?us
135
136     _LCDPORT_CONT_EN = 1; // Disable EN
137 //    _LCDPORT_CONT_LATCH = b;
138     _ACM1602_TC_WAIT(); // Wait 2.5?us
139
140     _LCDPORT_CONT_EN = 0;; // Disable EN
141 //    _LCDPORT_CONT_LATCH = b;
142     _ACM1602_TC_WAIT(); // Wait 2.5?us
143
144     b = _LCDPORT_TRIS_DATA;
145     b &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
146     _LCDPORT_TRIS_DATA = b;
147     _ACM1602_TC_WAIT(); // Wait 2.5?us
148
149     if((d & _LCDPORT_BUSYMASK) != 0){
150         d = 0xff; // BUSY
151     } else {
152         d = 0;
153     }
154     return d;
155 }
156
157 void lcd_waitbusy(unsigned char addr, unsigned char flag)
158 {
159     unsigned char f,ff;
160     ff = flag;
161     if(ff != 0) ff = 0xff;
162     do {
163         f = lcd_busychk(addr);
164         _ACM1602_SHORT_WAIT(); // Wait 0.1ms
165     } while(f != ff);
166 }
167
168 static void sendcmd(unsigned char addr, unsigned char cmd,unsigned char busyflag)
169 {
170 #ifdef _LCD_IF_4BIT
171     unsigned char b, d;
172     unsigned char h,l;
173
174     h = cmd & 0xf0; // Higher bit is used.
175     l = (cmd & 0x0f) << 4; // Higher bit is used.
176     // Higher NIBBLE
177     if(busyflag != 0) lcd_waitbusy(addr, 0);
178     d = _LCDPORT_TRIS_CONT;
179     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
180     _LCDPORT_TRIS_CONT = d;
181
182     _LCDPORT_CONT_RW = 0;
183     _LCDPORT_CONT_EN = 0;
184     _LCDPORT_CONT_RS = 0;
185     _LCDPORT_CONT_LATCH &= 0x0f; // Upper
186 //    b &= ~(_LCDPORT_CONT_RW | 0xf0 | _LCDPORT_CONT_EN | _LCDPORT_CONT_RS); // DATA=blank,RW='0',RS='0"
187     _LCDPORT_CONT_LATCH |= h;
188 //    _LCDPORT_CONT_LATCH = b;
189     _ACM1602_TC_WAIT(); // Wait 2.5?us
190
191     _LCDPORT_CONT_EN = 1;
192     //_LCDPORT_CONT_LATCH = b;
193     _ACM1602_TC_WAIT(); // Wait 2.5?us
194
195     _LCDPORT_CONT_EN = 0; // Disable EN
196 //    _LCDPORT_CONT_LATCH = b;
197     _ACM1602_TC_WAIT();
198
199     // Lower NIBBLE
200 //    if(busyflag != 0) lcd_waitbusy(addr, 0);
201 //    d = _LCDPORT_TRIS_CONT;
202 //    d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
203 //    _LCDPORT_TRIS_CONT = d;
204
205     _LCDPORT_CONT_RW = 0;
206     _LCDPORT_CONT_EN = 0;
207     _LCDPORT_CONT_RS = 0;
208     _LCDPORT_CONT_LATCH &= 0x0f; // Lower
209
210     _LCDPORT_CONT_LATCH |= l;
211     _ACM1602_TC_WAIT(); // Wait 2.5?us
212     _LCDPORT_CONT_EN = 1;
213 //    _LCDPORT_CONT_LATCH = b;
214
215     _ACM1602_TC_WAIT(); // Wait 2.5?us
216     _LCDPORT_CONT_EN = 0; // Disable EN
217 //    _LCDPORT_CONT_LATCH = b;
218
219 //    d = _LCDPORT_TRIS_CONT;
220  //   d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
221   //  _LCDPORT_TRIS_CONT = d;
222
223 #else
224     unsigned char b,d;
225
226     if(busyflag != 0) lcd_waitbusy(addr, 0);
227     d = _LCDPORT_TRIS_DATA;
228     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
229     _LCDPORT_TRIS_DATA = d;
230
231     b = _LCDPORT_CONT_LATCH;
232     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN); // RS='0',RW='0'
233     _LCDPORT_CONT_LATCH = b;
234
235     _LCDPORT_LATCH_DATA = cmd;
236
237     b |= _LCDPORT_CONT_EN; // Send CMD
238     _LCDPORT_CONT_LATCH = b;
239     _ACM1602_TC_WAIT(); // Wait 2.5?us
240
241     b &= ~_LCDPORT_CONT_EN; // Disable EN
242     _LCDPORT_CONT_LATCH = b;
243
244     d = _LCDPORT_TRIS_DATA;
245     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
246     _LCDPORT_TRIS_DATA = d;
247
248 #endif
249     // End of Command.
250     _ACM1602_SHORT_WAIT(); // Wait 50us
251 }
252
253 static void sendonce(unsigned char addr, unsigned char cmd)
254 {
255 #ifdef _LCD_IF_4BIT
256     unsigned char b, d;
257     unsigned char h;
258
259     h = cmd & 0xf0; // Higher bit is used.
260     // Higher NIBBLE
261     //d = _LCDPORT_TRIS_CONT;
262 //    d = TRIS_D_VAL; // Clear mask for Tristate, direction = write.
263 //    _LCDPORT_TRIS_CONT = d;
264     d = _LCDPORT_TRIS_CONT;
265     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
266     _LCDPORT_TRIS_CONT = d;
267
268     _LCDPORT_CONT_RS = 0;
269     _LCDPORT_CONT_RW = 0;
270     _LCDPORT_CONT_EN = 0; // RS='0',RW='0'
271     _LCDPORT_CONT_LATCH &= 0x0f;
272     _LCDPORT_CONT_LATCH |= h;
273     _ACM1602_TC_WAIT(); // Wait 2.5?us
274
275     _LCDPORT_CONT_EN = 1; // Send CMD
276     _ACM1602_TC_WAIT(); // Wait 2.5?us
277
278     _LCDPORT_CONT_EN = 0; // Disable EN
279     _ACM1602_TC_WAIT();
280
281 //    d = _LCDPORT_TRIS_CONT;
282 //    d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
283 //    _LCDPORT_TRIS_CONT = d;
284
285 #else
286     unsigned char b, d;
287
288     d = _LCDPORT_TRIS_DATA;
289     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
290     _LCDPORT_TRIS_DATA = d;
291
292     b = _LCDPORT_CONT_LATCH;
293     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN); // RS='0',RW='0'
294     _LCDPORT_CONT_LATCH = b;
295
296     _LCDPORT_LATCH_DATA = cmd;
297
298     b |= _LCDPORT_CONT_EN; // Send CMD
299     _LCDPORT_CONT_LATCH = b;
300     _ACM1602_TC_WAIT(); // Wait 2.5?us
301
302     b &= ~_LCDPORT_CONT_EN; // Disable EN
303     _LCDPORT_CONT_LATCH = b;
304 //    _ACM1602_TC_WAIT();
305 #endif
306     _ACM1602_SHORT_WAIT(); // Wait 50us
307 }
308
309 static void acm1602_ioinit(unsigned char addr)
310 {
311     unsigned char b;
312
313 //    lcd_waitbusy(0);
314     _ACM1602_LONG_LONG_WAIT();
315 #ifdef _LCD_IF_4BIT
316     _LCDPORT_TRIS_CONT = TRIS_D_VAL;
317
318     _LCDPORT_CONT_RS = 0;
319     _LCDPORT_CONT_RW = 0;
320     _LCDPORT_CONT_EN = 0;
321     _LCDPORT_CONT_LATCH &= ~0xf0;
322 //    _LCDPORT_CONT_LATCH = b;
323   //  _LCDPORT_TRIS_DATA = 0x00; // OUT
324   //  _LCDPORT_LATCH_DATA = 0x00;
325 #else
326     b = _LCDPORT_TRIS_CONT;
327     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN);
328     _LCDPORT_TRIS_CONT = b; // Clear Tristate bits, output.
329     b = _LCDPORT_CONT_LATCH;
330     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN);
331     _LCDPORT_CONT_LATCH = b;
332     _LCDPORT_TRIS_DATA = 0x00; // OUT
333     _LCDPORT_LATCH_DATA = 0x00;
334 #endif
335 }
336
337
338 void acm1602_putchar(unsigned char addr, unsigned char c)
339 {
340     unsigned char b, d;
341 #ifdef _LCD_IF_4BIT
342     unsigned char h, l;
343     h = c & 0xf0;
344     l = (c & 0x0f)<<4;
345
346     lcd_waitbusy(addr, 0);
347 //    d = _LCDPORT_TRIS_CONT;
348 //    d &= 0x00; // Clear mask for Tristate, direction = write.
349     d = TRIS_D_VAL; // ALL OUT
350     _LCDPORT_TRIS_CONT = d;
351     _ACM1602_TC_WAIT(); // Wait 2.5?us
352
353     // Send high nibble
354     //b = _LCDPORT_CONT_LATCH;
355     _LCDPORT_CONT_RW = 0;
356     _LCDPORT_CONT_EN = 0; // DATA=blank,RW='0'
357     _LCDPORT_CONT_LATCH &= ~0xf0;
358     _LCDPORT_CONT_RS = 1; // RS='1"
359 //    _LCDPORT_CONT_LATCH = b;
360     _ACM1602_TC_WAIT(); // Wait 2.5?us
361
362     _LCDPORT_CONT_EN = 1; // Do high write.
363 //    b |= h;
364     _LCDPORT_CONT_LATCH |= h;
365     _ACM1602_TC_WAIT(); // Wait 2.5?us
366
367     _LCDPORT_CONT_EN = 0; // Disable EN
368 //    _LCDPORT_CONT_LATCH = b;
369     _ACM1602_SHORT_WAIT();
370
371 //    lcd_waitbusy(addr, 0);
372     _LCDPORT_CONT_LATCH &= ~0xf0;
373     _LCDPORT_CONT_RS = 1; // RS='1"
374     _ACM1602_TC_WAIT(); // Wait 2.5?us
375
376     _LCDPORT_CONT_LATCH |= l; // Do low write.
377     _LCDPORT_CONT_EN = 1;
378     _ACM1602_TC_WAIT(); // Wait 2.5?us
379
380     _LCDPORT_CONT_EN = 0; // Disable EN
381     _ACM1602_SHORT_WAIT();
382
383
384 #else
385     lcd_waitbusy(addr, 0);
386     d = _LCDPORT_TRIS_DATA;
387     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
388     _LCDPORT_TRIS_DATA = d;
389
390     b = _LCDPORT_CONT_LATCH;
391     b &= ~_LCDPORT_CONT_RW; // ,RW='0'
392     b |= _LCDPORT_CONT_RS; // RS='1"
393     _LCDPORT_LATCH_DATA = c;
394     _LCDPORT_CONT_LATCH = b;
395     _ACM1602_TC_WAIT(); // Wait 2.5?us
396
397     b |= _LCDPORT_CONT_EN; // Send character
398     _LCDPORT_CONT_LATCH = b;
399     _ACM1602_TC_WAIT(); // Wait 2.5?us
400
401     b &= ~_LCDPORT_CONT_EN; // Disable EN
402     _LCDPORT_CONT_LATCH = b;
403     _ACM1602_SHORT_WAIT(); // Wait 0.1ms
404 #endif
405 }
406
407 #endif
408
409 void acm1602_cls(unsigned char addr)
410 {
411     sendcmd(addr, 0x01, 0xff);
412     _ACM1602_LONG_LONG_WAIT(); // Wait 5ms
413 }
414
415 void acm1602_setdataramaddress(unsigned char addr, unsigned char pos)
416 {
417     unsigned char cmd = (pos & 0x7f) | 0x80;
418     sendcmd(addr, cmd, 0xff);
419 }
420
421 void acm1602_locate_16x2(unsigned char addr, char x, char y)
422 {
423     unsigned char ramaddr;
424     ramaddr = (y == 0)? x & 0x0f : (x & 0x0f) | 0x40;
425     acm1602_setdataramaddress(addr, ramaddr);
426 }
427
428 /*
429  * For using
430  */
431 void acm1602_locate_8x2(unsigned char addr, char x, char y)
432 {
433     unsigned char ramaddr;
434     if((x < 0) || (x > 8)) return;
435     if((y < 0) || (y > 1)) return;
436     ramaddr = (y == 0)? x & 0x0f : (x & 0x0f) | 0x40;
437     acm1602_setdataramaddress(addr, ramaddr);
438 }
439
440 void acm1602_home(unsigned char addr)
441 {
442     sendcmd(addr, 0x02, 0xff);
443     _ACM1602_LONG_LONG_WAIT(); // Wait 5ms
444 }
445
446
447 void acm1602_cursordir(unsigned char addr, unsigned char right)
448 {
449     unsigned char cmd;
450     if(right == 0) {
451         cmd = 0x18;
452     } else {
453         cmd = 0x1c;
454     }
455     sendcmd(addr, cmd, 0xff);
456 }
457
458 void acm1602_setcgramaddress(unsigned char addr, unsigned char pos)
459 {
460     unsigned char cmd = (pos & 0x3f) | 0x40;
461     sendcmd(addr, cmd, 0xff);
462 }
463
464 void acm1602_init(unsigned char addr, unsigned char cls)
465 {
466     acm1602_ioinit(addr);
467 #ifdef _USE_I2C_1602
468     sendcmd(addr,0x01,0x00);
469     sendcmd(addr, 0x38, 0x00); // 2lines, 8x10dot fonts.
470 //    sendcmd(addr, 0x38, 0x00); // 2lines, 8x10dot fonts.
471 #else
472   #ifndef _LCD_IF_4BIT
473     sendonce(addr, 0x38); // 2lines, 8x10dot fonts.
474     sendcmd(addr, 0x38, 0x00); // 2lines, 8x10dot fonts.
475   #else // 4Bit
476     _ACM1602_LONG_LONG_WAIT();
477     sendonce(addr, 0x30); // 2lines, 8x10dot fonts.
478     _ACM1602_SHORT_WAIT();
479     sendonce(addr, 0x30); // 2lines, 8x10dot fonts.
480     _ACM1602_SHORT_WAIT();
481     sendonce(addr, 0x30); // 2lines, 8x10dot fonts.
482     _ACM1602_SHORT_WAIT();
483     sendonce(addr, 0x20); // 2lines, 8x10dot fonts.
484     _ACM1602_SHORT_WAIT();
485     // Send twice on 4Bit Mode.
486 //    sendonce(addr, 0x30); // 2lines, 8x10dot fonts.
487     sendcmd(addr, 0x28, 0xff); // 2lines, 8x5dot fonts.
488   #endif
489 #endif
490 //    sendcmd(addr, 0x08, 0xff); // Display OFF.
491     sendcmd(addr, 0x0c, 0xff); // Display ON.
492     sendcmd(addr, 0x06, 0xff); // Cursor increment,not shift.
493    if(cls == 0){
494         acm1602_home(addr);
495     } else {
496         acm1602_cls(addr);
497     }
498     _ACM1602_LONG_WAIT();
499 //    sendcmd(addr, 0x06, 0xff);
500 }
501
502 /*
503  * Suspend lcd
504  */
505 void acm1602_suspend(unsigned char addr)
506 {
507     sendcmd(addr, 0x08, 0xff);
508     _ACM1602_LONG_WAIT();
509 }
510
511 #ifdef _USE_I2C_1602
512 /*
513  * st7032 extensions.
514  */
515 void st7032_extcmd(unsigned char addr, unsigned char mode, 
516         unsigned char cmd, unsigned char busyf)
517 {
518     unsigned char m = mode & 0x1c;
519     m = m | 0x21;
520     sendcmd(addr, m, busyf); // Shift to IS1
521     sendcmd(addr, cmd, busyf);
522     m &= 0xfe; // Shift to IS0
523     sendcmd(addr, m, busyf);
524 }
525
526 void st7032_setcontrast(unsigned char addr, unsigned char value,
527         unsigned char busyf)
528 {
529     unsigned char val = value & 0x0f;
530     val |= 0x70;
531     st7032_extcmd(addr, 0x38, val, busyf);
532 }
533 #endif