OSDN Git Service

fbf212d0ff907ebd75bca61ed27e390cb8b9a9f6
[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(void)
34 {
35     unsigned char b, d;
36     // Under development.
37     d = 0xff;
38     if((d & _LCDPORT_BUSYMASK) != 0){
39         d = 0xff; // BUSY
40     } else {
41         d = 0;
42     }
43     return d;
44 }
45
46 static void lcd_waitbusy(unsigned char flag)
47 {
48     unsigned char f,ff;
49     ff = flag;
50     if(ff != 0) ff = 0xff;
51     do {
52         f = lcd_busychk();
53         _ACM1602_SHORT_WAIT(); // Wait 0.1ms
54     } while(f != ff);
55 }
56
57
58 static void sendcmd(unsigned char addr, unsigned char cmd, unsigned char busyflag)
59 {
60     i2c_idle();
61     OPENASMASTER();
62     i2c_writechar(addr);
63     i2c_writechar(0x00);
64     i2c_writechar(cmd);
65     CLOSEASMASTER();
66     _ACM1602_I2C_WAIT(); // 0.2ms
67 }
68
69 static void sendonce(unsigned char addr, unsigned char cmd)
70 {
71     sendcmd(addr, cmd, 0x00);
72 }
73
74 static void acm1602_ioinit(unsigned char addr)
75 {
76     _ACM1602_LONG_LONG_WAIT();
77     return;
78 }
79
80 void acm1602_putchar(unsigned char addr, unsigned char c)
81 {
82     i2c_idle();
83     OPENASMASTER();
84     i2c_writechar(addr);
85     i2c_writechar(0x80); //Data
86     i2c_writechar(c); // Putchar
87     CLOSEASMASTER();
88     _ACM1602_SHORT_WAIT(); // Wait 50us
89 }
90
91 unsigned char acm1602_getchar(unsigned char addr)
92 {
93     // Under development
94     return 0x00;
95 }
96 #else // Parallel
97 static unsigned char lcd_busychk(void)
98 {
99     unsigned char b, d;
100
101     // Set mask for Tristate.
102     b = _LCDPORT_TRIS_DATA;
103     b |= _LCDPORT_READMASK;// Set mask for Tristate, direction = read.
104     _LCDPORT_TRIS_DATA = b;
105
106     b = _LCDPORT_CONT_LATCH;
107     b &= ~_LCDPORT_CONT_RS;
108     b |= _LCDPORT_CONT_RW;
109     _LCDPORT_CONT_LATCH = b;
110     b |= _LCDPORT_CONT_EN; // Send CMD
111     _LCDPORT_CONT_LATCH = b;
112     _ACM1602_TC_WAIT(); // Wait 2.5?us
113     d = _LCDPORT_DATA;
114     b &= ~_LCDPORT_CONT_EN; // Disable EN
115     _LCDPORT_CONT_LATCH = b;
116
117     b = _LCDPORT_TRIS_DATA;
118     b &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
119     _LCDPORT_TRIS_DATA = b;
120
121     if((d & _LCDPORT_BUSYMASK) != 0){
122         d = 0xff; // BUSY
123     } else {
124         d = 0;
125     }
126     return d;
127 }
128
129 static void lcd_waitbusy(unsigned char flag)
130 {
131     unsigned char f,ff;
132     ff = flag;
133     if(ff != 0) ff = 0xff;
134     do {
135         f = lcd_busychk();
136         _ACM1602_SHORT_WAIT(); // Wait 0.1ms
137     } while(f != ff);
138 }
139
140 static void sendcmd(unsigned char addr, unsigned char cmd,unsigned char busyflag)
141 {
142 #ifdef _LCD_IF_4BIT
143     unsigned char b, d;
144     unsigned char h,l;
145
146     h = cmd & 0xf0; // Higher bit is used.
147     l = (cmd & 0x0f) << 4; // Higher bit is used.
148     // Higher NIBBLE
149     if(busyflag != 0) lcd_waitbusy(0);
150     d = _LCDPORT_TRIS_CONT;
151     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
152     _LCDPORT_TRIS_CONT = d;
153
154
155     b = _LCDPORT_CONT_LATCH;
156     b &= ~(_LCDPORT_CONT_RW | 0xf0 | _LCDPORT_CONT_EN | _LCDPORT_CONT_RS); // DATA=blank,RW='0',RS='0"
157     b |= h;
158     _LCDPORT_CONT_LATCH = b;
159     _ACM1602_TC_WAIT(); // Wait 2.5?us
160     b |= _LCDPORT_CONT_EN;
161     _LCDPORT_CONT_LATCH = b;
162     _ACM1602_TC_WAIT(); // Wait 2.5?us
163     b &= ~_LCDPORT_CONT_EN; // Disable EN
164     _LCDPORT_CONT_LATCH = b;
165     _ACM1602_TC_WAIT();
166
167     // Lower NIBBLE
168     if(busyflag != 0) lcd_waitbusy(0);
169     d = _LCDPORT_TRIS_CONT;
170     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
171     _LCDPORT_TRIS_CONT = d;
172     b = _LCDPORT_CONT_LATCH;
173     b &= ~(_LCDPORT_CONT_RW | 0xf0 | _LCDPORT_CONT_EN | _LCDPORT_CONT_RS); // DATA=blank,RW='0',RS='0"
174     b |= l;
175     _LCDPORT_CONT_LATCH = b;
176     _ACM1602_TC_WAIT(); // Wait 2.5?us
177     b |= _LCDPORT_CONT_EN;
178     _LCDPORT_CONT_LATCH = b;
179     _ACM1602_TC_WAIT(); // Wait 2.5?us
180     b &= ~_LCDPORT_CONT_EN; // Disable EN
181     _LCDPORT_CONT_LATCH = b;
182
183     d = _LCDPORT_TRIS_CONT;
184     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
185     _LCDPORT_TRIS_CONT = d;
186
187 #else
188     unsigned char b,d;
189
190     if(busyflag != 0) lcd_waitbusy(0);
191     d = _LCDPORT_TRIS_DATA;
192     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
193     _LCDPORT_TRIS_DATA = d;
194
195     b = _LCDPORT_CONT_LATCH;
196     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN); // RS='0',RW='0'
197     _LCDPORT_CONT_LATCH = b;
198
199     _LCDPORT_LATCH_DATA = cmd;
200
201     b |= _LCDPORT_CONT_EN; // Send CMD
202     _LCDPORT_CONT_LATCH = b;
203     _ACM1602_TC_WAIT(); // Wait 2.5?us
204
205     b &= ~_LCDPORT_CONT_EN; // Disable EN
206     _LCDPORT_CONT_LATCH = b;
207
208     d = _LCDPORT_TRIS_DATA;
209     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
210     _LCDPORT_TRIS_DATA = d;
211
212 #endif
213     // End of Command.
214     _ACM1602_SHORT_WAIT(); // Wait 50us
215 }
216
217 static void sendonce(unsigned char addr, unsigned char cmd)
218 {
219 #ifdef _LCD_IF_4BIT
220     unsigned char b, d;
221     unsigned char h;
222
223     h = cmd & 0xf0; // Higher bit is used.
224     // Higher NIBBLE
225     d = _LCDPORT_TRIS_CONT;
226     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
227     _LCDPORT_TRIS_CONT = d;
228
229     b = _LCDPORT_CONT_LATCH;
230     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN); // RS='0',RW='0'
231     b |= h;
232     _LCDPORT_CONT_LATCH = b;
233
234     b |= _LCDPORT_CONT_EN; // Send CMD
235     _LCDPORT_CONT_LATCH = b;
236     _ACM1602_TC_WAIT(); // Wait 2.5?us
237
238     b &= ~_LCDPORT_CONT_EN; // Disable EN
239     _LCDPORT_CONT_LATCH = b;
240     _ACM1602_TC_WAIT();
241
242     d = _LCDPORT_TRIS_CONT;
243     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
244     _LCDPORT_TRIS_CONT = d;
245
246 #else
247     unsigned char b, d;
248
249     d = _LCDPORT_TRIS_DATA;
250     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
251     _LCDPORT_TRIS_DATA = d;
252
253     b = _LCDPORT_CONT_LATCH;
254     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN); // RS='0',RW='0'
255     _LCDPORT_CONT_LATCH = b;
256
257     _LCDPORT_LATCH_DATA = cmd;
258
259     b |= _LCDPORT_CONT_EN; // Send CMD
260     _LCDPORT_CONT_LATCH = b;
261     _ACM1602_TC_WAIT(); // Wait 2.5?us
262
263     b &= ~_LCDPORT_CONT_EN; // Disable EN
264     _LCDPORT_CONT_LATCH = b;
265 //    _ACM1602_TC_WAIT();
266 #endif
267     _ACM1602_SHORT_WAIT(); // Wait 50us
268 }
269
270 static void acm1602_ioinit(unsigned char addr)
271 {
272     unsigned char b;
273
274 //    lcd_waitbusy(0);
275     _ACM1602_LONG_LONG_WAIT();
276 #ifdef _LCD_IF_4BIT
277     b = _LCDPORT_TRIS_CONT;
278     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN | 0xf0);
279     _LCDPORT_TRIS_CONT = b; // Clear Tristate bits, output.
280
281     b = _LCDPORT_CONT_LATCH;
282     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN | 0xf0);
283     _LCDPORT_CONT_LATCH = b;
284
285     //_LCDPORT_TRIS_DATA = 0x00; // OUT
286     //_LCDPORT_LATCH_DATA = 0x00;
287 #else
288     b = _LCDPORT_TRIS_CONT;
289     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN);
290     _LCDPORT_TRIS_CONT = b; // Clear Tristate bits, output.
291     b = _LCDPORT_CONT_LATCH;
292     b &= ~(_LCDPORT_CONT_RS | _LCDPORT_CONT_RW | _LCDPORT_CONT_EN);
293     _LCDPORT_CONT_LATCH = b;
294     _LCDPORT_TRIS_DATA = 0x00; // OUT
295     _LCDPORT_LATCH_DATA = 0x00;
296 #endif
297 }
298
299
300 void acm1602_putchar(unsigned char addr, unsigned char c)
301 {
302     unsigned char b, d;
303 #ifdef _LCD_IF_4BIT
304     unsigned char h, l;
305     h = c & 0xf0;
306     l = (c & 0x0f)<<4;
307
308     lcd_waitbusy(0);
309     d = _LCDPORT_TRIS_CONT;
310     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
311     _LCDPORT_TRIS_CONT = d;
312
313     // Send high nibble
314     b = _LCDPORT_CONT_LATCH;
315     b &= ~(_LCDPORT_CONT_RW | 0xf0 | _LCDPORT_CONT_EN); // DATA=blank,RW='0'
316     b |= _LCDPORT_CONT_RS; // RS='1"
317     b |= h;
318     _LCDPORT_CONT_LATCH = b;
319     _ACM1602_TC_WAIT(); // Wait 2.5?us
320
321     b |= _LCDPORT_CONT_EN; // Do high write.
322     _LCDPORT_CONT_LATCH = b;
323     _ACM1602_TC_WAIT(); // Wait 2.5?us
324
325     b &= ~_LCDPORT_CONT_EN; // Disable EN
326     _LCDPORT_CONT_LATCH = b;
327     _ACM1602_TC_WAIT();
328
329     lcd_waitbusy(0);
330     d = _LCDPORT_TRIS_CONT;
331     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
332     _LCDPORT_TRIS_CONT = d;
333
334     b = _LCDPORT_CONT_LATCH;
335     b &= ~(_LCDPORT_CONT_RW | 0xf0 | _LCDPORT_CONT_EN); // DATA=blank,RW='0'
336     b |= _LCDPORT_CONT_RS; // RS='1"
337     b |= l;
338     _LCDPORT_CONT_LATCH = b;
339     _ACM1602_TC_WAIT(); // Wait 2.5?us
340
341     b |= _LCDPORT_CONT_EN;
342     _LCDPORT_CONT_LATCH = b; // Do low write.
343     _ACM1602_TC_WAIT(); // Wait 2.5?us
344
345     b &= ~_LCDPORT_CONT_EN; // Disable EN
346     _LCDPORT_CONT_LATCH = b;
347     _ACM1602_SHORT_WAIT();
348
349 #else
350     lcd_waitbusy(0);
351     d = _LCDPORT_TRIS_DATA;
352     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = write.
353     _LCDPORT_TRIS_DATA = d;
354
355     b = _LCDPORT_CONT_LATCH;
356     b &= ~_LCDPORT_CONT_RW; // ,RW='0'
357     b |= _LCDPORT_CONT_RS; // RS='1"
358     _LCDPORT_LATCH_DATA = c;
359     _LCDPORT_CONT_LATCH = b;
360     _ACM1602_TC_WAIT(); // Wait 2.5?us
361
362     b |= _LCDPORT_CONT_EN; // Send character
363     _LCDPORT_CONT_LATCH = b;
364     _ACM1602_TC_WAIT(); // Wait 2.5?us
365
366     b &= ~_LCDPORT_CONT_EN; // Disable EN
367     _LCDPORT_CONT_LATCH = b;
368     _ACM1602_SHORT_WAIT(); // Wait 0.1ms
369 #endif
370 }
371
372 unsigned char acm1602_getchar(unsigned char addr)
373 {
374     unsigned char b, d;
375 #ifdef _LCD_IF_4BIT
376     unsigned char h, l;
377
378     lcd_waitbusy(0);
379     d = _LCDPORT_TRIS_CONT;
380     d |= _LCDPORT_READMASK; // Set mask for Tristate, direction = read.
381     _LCDPORT_TRIS_CONT = d;
382
383     // Recv high nibble
384     b = _LCDPORT_CONT_LATCH;
385     b &= ~(0xf0 | _LCDPORT_CONT_EN); // DATA=blank
386     b |= (_LCDPORT_CONT_RS | _LCDPORT_CONT_RW); // RS='1", RW='1'
387     _LCDPORT_CONT_LATCH = b;
388     _ACM1602_TC_WAIT(); // Wait 2.5?us
389
390     b |= _LCDPORT_CONT_EN;
391     _LCDPORT_CONT_LATCH = b;
392     _ACM1602_TC_WAIT(); // Wait 2.5?us
393
394     h = _LCDPORT_DATA & 0xf0;
395     _ACM1602_TC_WAIT(); // Wait 2.5?us
396
397     b &= ~_LCDPORT_CONT_EN; // Disable EN
398     _LCDPORT_CONT_LATCH = b;
399     _ACM1602_TC_WAIT();
400
401     lcd_waitbusy(0);
402     // Recv Low nibble.
403     d = _LCDPORT_TRIS_CONT;
404     d |= _LCDPORT_READMASK; // Set mask for Tristate, direction = read.
405     _LCDPORT_TRIS_CONT = d;
406
407     b = _LCDPORT_CONT_LATCH;
408     b &= ~(0xf0 | _LCDPORT_CONT_EN); // DATA=blank
409     b |= (_LCDPORT_CONT_RS | _LCDPORT_CONT_RW); // RS='1", RW='1'
410     _LCDPORT_CONT_LATCH = b;
411     _ACM1602_TC_WAIT(); // Wait 2.5?us
412
413     b |= _LCDPORT_CONT_EN;
414     _LCDPORT_CONT_LATCH = b;
415     _ACM1602_TC_WAIT(); // Wait 2.5?us
416
417     l = _LCDPORT_DATA & 0xf0;
418     _ACM1602_TC_WAIT(); // Wait 2.5?us
419
420     b &= ~_LCDPORT_CONT_EN; // Disable EN
421     _LCDPORT_CONT_LATCH = b;
422     _ACM1602_TC_WAIT(); // Wait 2.5?us
423
424     d = _LCDPORT_TRIS_CONT;
425     d &= ~_LCDPORT_READMASK; // Set mask for Tristate, direction = write.
426     _LCDPORT_TRIS_CONT = d;
427
428     _ACM1602_SHORT_WAIT();
429
430     d = h | (l >> 4);
431     return d;
432 #else
433     unsigned char e;
434     lcd_waitbusy(0);
435     d = _LCDPORT_TRIS_DATA;
436     d |= _LCDPORT_READMASK; // Set mask for Tristate, direction = read.
437     _LCDPORT_TRIS_DATA = d;
438
439     b = _LCDPORT_CONT_LATCH;
440     b |= (_LCDPORT_CONT_RS | _LCDPORT_CONT_RW); // RW=1, RS=1
441     b &= ~_LCDPORT_CONT_EN; // Clear Enable
442     _LCDPORT_CONT_LATCH = b;
443     _ACM1602_TC_WAIT();
444
445     b |= _LCDPORT_CONT_EN; // Send character
446     _LCDPORT_CONT_LATCH = b;
447     _ACM1602_TC_WAIT(); // Wait 2.5?us
448
449     e = _LCDPORT_DATA; // Read BYTE
450     _ACM1602_TC_WAIT();
451
452     b &= ~_LCDPORT_CONT_EN; // Disable EN
453     _LCDPORT_CONT_LATCH = b;
454
455     d = _LCDPORT_TRIS_DATA;
456     d &= ~_LCDPORT_READMASK; // Clear mask for Tristate, direction = read.
457     _LCDPORT_TRIS_DATA = d;
458
459     _ACM1602_SHORT_WAIT(); // Wait 0.1ms
460     return e;
461 #endif
462 }
463
464 #endif
465
466 void acm1602_cls(unsigned char addr)
467 {
468     sendcmd(addr, 0x01, 0xff);
469     _ACM1602_LONG_WAIT(); // Wait 5ms
470 }
471
472 void acm1602_locate(unsigned char addr, char x, char y)
473 {
474     unsigned char ramaddr;
475     if((x < 0) || (x > 15)) return;
476     if((y < 0) || (y > 1)) return;
477     if(y == 0){
478         ramaddr = 0x80 | (x & 0x0f);
479     } else {
480         ramaddr = 0xc0 | (x & 0x0f);
481     }
482     sendcmd(addr, ramaddr, 0xff);
483 }
484
485 void acm1602_home(unsigned char addr)
486 {
487     sendcmd(addr, 0x02, 0xff);
488     _ACM1602_LONG_WAIT(); // Wait 5ms
489 }
490
491 void acm1602_printf(unsigned char addr, const char *fmt, ...)
492 {
493     char strbuf[32]; // Max 32 bytes.
494     va_list args;
495     int i;
496     int l;
497
498     strbuf[0] = '\0';
499     va_start(args, fmt );
500     sprintf(strbuf, args);
501     l = strlen(strbuf);
502     if((l >= 32) || (l <= 0))return;
503     for(i = 0; i < l; i++) {
504         acm1602_putchar(addr, strbuf[i]);
505     }
506 }
507
508 void acm1602_cursordir(unsigned char addr, unsigned char right)
509 {
510     unsigned char cmd;
511     if(right == 0) {
512         cmd = 0x18;
513     } else {
514         cmd = 0x1c;
515     }
516     sendcmd(addr, cmd, 0xff);
517 }
518
519 void acm1602_init(unsigned char addr, unsigned char cls)
520 {
521     acm1602_ioinit(addr);
522 #ifdef _USE_I2C_1602
523     sendonce(addr, 0x38, 0x00); // 2lines, 8x10dot fonts.
524     _ACM1602_SHORT_WAIT();
525     sendcmd(addr, 0x38, 0x00); // 2lines, 8x10dot fonts.
526     _ACM1602_SHORT_WAIT();
527 #else
528   #ifndef _LCD_IF_4BIT
529     sendonce(addr, 0x38); // 2lines, 8x10dot fonts.
530     _ACM1602_SHORT_WAIT();
531     sendcmd(addr, 0x38, 0x00); // 2lines, 8x10dot fonts.
532     _ACM1602_SHORT_WAIT();
533   #else
534     sendonce(addr, 0x30); // 2lines, 8x10dot fonts.
535     _ACM1602_SHORT_WAIT();
536     // Send twice on 4Bit Mode.
537     sendcmd(addr, 0x28, 0x00); // 2lines, 8x10dot fonts.
538     _ACM1602_SHORT_WAIT();
539     sendcmd(addr, 0x28, 0x00); // 2lines, 8x10dot fonts.
540     _ACM1602_SHORT_WAIT();
541   #endif
542 #endif
543     sendcmd(addr, 0x0f, 0xff); // Display ON.
544     _ACM1602_SHORT_WAIT();
545     if(cls == 0){
546         acm1602_home(addr);
547     } else {
548         acm1602_cls(addr);
549     }
550     sendcmd(addr, 0b00000110, 0xff); // Cursor increment,not shift.
551     _ACM1602_SHORT_WAIT();
552 }