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