Specific the directory for all hw and cfg module. Use double quote for cfg and hw...
[bertos.git] / bertos / drv / lcd_hd44.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This 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.  See the
14  * 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 program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief LM044L type LCD hardware module (impl.)
34  *
35  * \version $Id$
36  * \author Bernardo Innocenti <bernie@develer.com>
37  * \author Stefano Fedrigo <aleph@develer.com>
38  */
39
40 #include "lcd_hd44.h"
41
42 #include "hw/hw_lcd.h"
43
44 #include "cfg/cfg_arch.h"
45
46 #include <drv/timer.h>
47
48 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
49         #define CONFIG_LCD_4BIT 1
50 #elif defined(LCD_READ) && defined(LCD_WRITE)
51         #define CONFIG_LCD_4BIT 0
52 #else
53         #error Incomplete or missing LCD_READ/LCD_WRITE macros
54 #endif
55
56 /** Flag di stato del display */
57 #define LCDF_BUSY  BV(7)
58
59 #if CONFIG_LCD_ADDRESS_FAST == 1
60 #define lcd_address(x) lcd_address[x]
61 /**
62  * Addresses of LCD display character positions, expanded
63  * for faster access (DB7 = 1).
64  */
65 static const uint8_t lcd_address[] =
66 {
67         /* row 0 */
68         0x80, 0x81, 0x82, 0x83,
69         0x84, 0x85, 0x86, 0x87,
70         0x88, 0x89, 0x8A, 0x8B,
71         0x8C, 0x8D, 0x8E, 0x8F,
72 #if LCD_COLS > 16
73         0x90, 0x91, 0x92, 0x93,
74 #endif
75
76         /* row 1 */
77         0xC0, 0xC1, 0xC2, 0xC3,
78         0xC4, 0xC5, 0xC6, 0xC7,
79         0xC8, 0xC9, 0xCA, 0xCB,
80         0xCC, 0xCD, 0xCE, 0xCF,
81 #if LCD_COLS > 16
82         0xD0, 0xD1, 0xD2, 0xD3,
83 #endif
84
85 #if LCD_ROWS > 2
86         /* row 2 */
87         0x94, 0x95, 0x96, 0x97,
88         0x98, 0x99, 0x9A, 0x9B,
89         0x9C, 0x9D, 0x9E, 0x9F,
90         0xA0, 0xA1, 0xA2, 0xA3,
91 #if LCD_COLS > 16
92         0xA4, 0xA5, 0xA6, 0xA7,
93 #endif
94
95         /* row 3 */
96         0xD4, 0xD5, 0xD6, 0xD7,
97         0xD8, 0xD9, 0xDA, 0xDB,
98         0xDC, 0xDD, 0xDE, 0xDF,
99         0xE0, 0xE1, 0xE2, 0xE3,
100 #if LCD_COLS > 16
101         0xE4, 0xE5, 0xE6, 0xE7,
102 #endif
103
104 #endif /* LCD_ROWS > 2 */
105 };
106
107 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
108 #else  /* CONFIG_LCD_ADDRESS_FAST == 0 */
109
110 static const uint8_t col_address[] =
111 {
112         0x80,
113         0xC0,
114 #if LCD_ROWS > 2
115         0x94,
116         0xD4
117 #endif
118 };
119 STATIC_ASSERT(countof(col_address) == LCD_ROWS);
120 /**
121  * Addresses of LCD display character positions, calculated runtime to save RAM
122  */
123 static uint8_t lcd_address(uint8_t addr)
124 {
125         return col_address[addr / LCD_COLS] + addr % LCD_COLS;
126 }
127 #endif /* CONFIG_LCD_ADDRESS_FAST */
128
129 /**
130  * Current display position. We remember this to optimize
131  * LCD output by avoiding to set the address every time.
132  */
133 static lcdpos_t lcd_current_addr;
134
135
136 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
137 /*      __________________
138  * RS
139  *
140  * R/W  __________________
141  *            _______
142  * ENA  _____/       \____
143  *
144  * DATA -<================
145  */
146 INLINE void lcd_dataWrite(uint8_t data)
147 {
148 #if CONFIG_LCD_4BIT
149         /* Write high nibble */
150         LCD_WRITE_H(data);
151         LCD_SET_E;
152         LCD_DELAY_WRITE;
153         LCD_CLR_E;
154         LCD_DELAY_WRITE;
155
156         /* Write low nibble */
157         LCD_WRITE_L(data);
158         LCD_SET_E;
159         LCD_DELAY_WRITE;
160         LCD_CLR_E;
161         LCD_DELAY_WRITE;
162
163 #else /* !CONFIG_LCD_4BIT */
164
165         /* Write data */
166         LCD_WRITE(data);
167         LCD_SET_E;
168         LCD_DELAY_WRITE;
169         LCD_CLR_E;
170         LCD_DELAY_WRITE;
171
172 #endif /* !CONFIG_LCD_4BIT */
173 }
174
175 /*      __________________
176  * RS
177  *         ____________
178  * R/W  __/            \__
179  *            _______
180  * ENA  _____/       \____
181  *        ______      ____
182  * DATA X/      \====/
183  */
184 INLINE uint8_t lcd_dataRead(void)
185 {
186         uint8_t data;
187
188         LCD_SET_RD;
189         LCD_DB_IN;      /* Set bus as input! */
190         LCD_DELAY_READ;
191
192 #if CONFIG_LCD_4BIT
193
194         /* Read high nibble */
195         LCD_SET_E;
196         LCD_DELAY_READ;
197         data = LCD_READ_H;
198         LCD_CLR_E;
199         LCD_DELAY_READ;
200
201         /* Read low nibble */
202         LCD_SET_E;
203         LCD_DELAY_READ;
204         data |= LCD_READ_L;
205         LCD_CLR_E;
206         LCD_DELAY_READ;
207
208 #else /* !CONFIG_LCD_4BIT */
209
210         /* Read data */
211         LCD_SET_E;
212         LCD_DELAY_READ;
213         data = LCD_READ;
214         LCD_CLR_E;
215         LCD_DELAY_READ;
216
217 #endif /* !CONFIG_LCD_4BIT */
218
219         LCD_CLR_RD;
220         LCD_DB_OUT;     /* Reset bus as output! */
221
222         return data;
223 }
224
225 /*      ___             __
226  * RS      \___________/
227  *
228  * READ __________________
229  *            _______
230  * ENA  _____/       \____
231  *
232  * DATA --<===============
233  */
234 INLINE void lcd_regWrite(uint8_t data)
235 {
236         LCD_CLR_RS;
237         lcd_dataWrite(data);
238         LCD_SET_RS;
239 }
240
241 /*      __               _
242  * RS     \_____________/
243  *          ___________
244  * READ ___/           \__
245  *            _______
246  * ENA  _____/       \____
247  *        ______      ____
248  * DATA X/      \====/
249  */
250 INLINE uint8_t lcd_regRead(void)
251 {
252         uint8_t data;
253
254         LCD_CLR_RS;
255         data = lcd_dataRead();
256         LCD_SET_RS;
257         return data;
258 }
259
260 #if CONFIG_LCD_4BIT
261
262 INLINE void lcd_mode4Bit(void)
263 {
264         LCD_CLR_RS;
265
266         LCD_WRITE_H(LCD_CMD_SETFUNC);
267         LCD_SET_E;
268         LCD_DELAY_WRITE;
269         LCD_CLR_E;
270         LCD_DELAY_WRITE;
271
272         LCD_SET_RS;
273 }
274
275 #endif /* CONFIG_LCD_4BIT */
276
277 #else /* ARCH_EMUL */
278
279 extern void Emul_LCDWriteReg(uint8_t d);
280 extern uint8_t Emul_LCDReadReg(void);
281 extern void Emul_LCDWriteData(uint8_t d);
282 extern uint8_t Emul_LCDReadData(void);
283
284 #define lcd_regWrite(d)   Emul_LCDWriteReg(d)
285 #define lcd_regRead(d)    Emul_LCDReadReg()
286 #define lcd_dataWrite(d)  Emul_LCDWriteData(d)
287 #define lcd_dataRead(d)   Emul_LCDReadData()
288
289 #endif /* ARCH_EMUL */
290
291
292 /**
293  * Wait until the LCD busy flag clears.
294  */
295 void lcd_waitBusy(void)
296 {
297         for (;;)
298         {
299                 uint8_t val = lcd_regRead();
300                 if (!(val & LCDF_BUSY))
301                         break;
302         }
303 }
304
305
306 /**
307  * Move the cursor to \a addr, only if not already there.
308  */
309 void lcd_moveTo(uint8_t addr)
310 {
311         if (addr != lcd_current_addr)
312         {
313                 lcd_waitBusy();
314                 lcd_regWrite(lcd_address(addr));
315                 lcd_current_addr = addr;
316         }
317 }
318
319
320 /**
321  * Write a value in LCD data register, waiting for the busy flag.
322  */
323 void lcd_setReg(uint8_t val)
324 {
325         lcd_waitBusy();
326         lcd_regWrite(val);
327 }
328
329 #include <cfg/debug.h>
330 /**
331  * Write the character \a c on display address \a addr.
332  *
333  * NOTE: argh, the HD44 lcd type is a bad beast: our
334  * move/write -> write optimization requires this mess
335  * because display lines are interleaved!
336  */
337 void lcd_putc(uint8_t addr, uint8_t c)
338 {
339         if (addr != lcd_current_addr)
340                 lcd_setReg(lcd_address(addr));
341
342         lcd_waitBusy();
343         lcd_dataWrite(c);
344         lcd_current_addr = addr + 1;
345
346         /* If we are at end of display wrap the address to 0 */
347         if (lcd_current_addr == LCD_COLS * LCD_ROWS)
348                 lcd_current_addr = 0;
349
350         /* If we are at the end of a row put the cursor at the beginning of the next */
351         if (!(lcd_current_addr % LCD_COLS))
352                 lcd_setReg(lcd_address(lcd_current_addr));
353 }
354
355
356 /**
357  * Remap the glyph of a character.
358  *
359  * glyph - bitmap of 8x8 bits.
360  * code - must be 0-7 for the Hitachi LCD-II controller.
361  */
362 void lcd_remapChar(const char *glyph, char code)
363 {
364         int i;
365
366         /* Set CG RAM address */
367         lcd_setReg((uint8_t)((1<<6) | (code << 3)));
368
369         /* Write bitmap data */
370         for (i = 0; i < 8; i++)
371         {
372                 lcd_waitBusy();
373                 lcd_dataWrite(glyph[i]);
374         }
375
376         /* Move back to original address */
377         lcd_setReg(lcd_address(lcd_current_addr));
378 }
379
380
381 #if 0 /* unused */
382 void lcd_remapfont(void)
383 {
384         static const char lcd_glyphs[8] =
385         {
386                 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
387         };
388         int i;
389
390         for (i = 0; i < 15; i++)
391                 lcd_remapChar(i, bernie_char);
392
393
394         lcd_setAddr(lcd_DefLayer, 0);
395         for (i = 0; i < 80; i++)
396                 lcd_putCharUnlocked(i);
397 }
398 #endif /* unused */
399
400 void lcd_hw_init(void)
401 {
402         lcd_bus_init();
403
404         timer_delay(50);
405
406 #if CONFIG_LCD_4BIT
407         lcd_mode4Bit();
408         timer_delay(2);
409 #endif /* CONFIG_LCD_4BIT */
410
411         lcd_regWrite(LCD_CMD_SETFUNC);
412         timer_delay(2);
413
414         lcd_regWrite(LCD_CMD_DISPLAY_ON);
415         timer_delay(2);
416
417         lcd_regWrite(LCD_CMD_CLEAR);
418         timer_delay(2);
419
420 #if !CONFIG_LCD_4BIT
421         lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
422 #endif
423         lcd_regWrite(LCD_CMD_DISPLAYMODE);
424         timer_delay(2);
425 }
426
427