4 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See README.devlib for information.
8 * \brief LM044L type LCD hardware module (impl.)
11 * \author Bernardo Innocenti <bernie@develer.com>
12 * \author Stefano Fedrigo <aleph@develer.com>
17 *#* Revision 1.3 2006/09/20 19:55:01 marco
18 *#* Added CONFIG_LCD_4BIT.
20 *#* Revision 1.2 2006/07/19 12:56:25 bernie
21 *#* Convert to new Doxygen style.
23 *#* Revision 1.1 2005/11/04 18:00:42 bernie
24 *#* Import into DevLib.
26 *#* Revision 1.2 2005/06/14 14:43:43 bernie
27 *#* Add DevLib headers.
29 *#* Revision 1.1 2005/05/24 09:17:58 batt
30 *#* Move drivers to top-level.
32 *#* Revision 1.9 2005/05/09 21:58:53 batt
35 *#* Revision 1.8 2005/05/09 12:52:46 batt
36 *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
38 *#* Revision 1.7 2005/05/09 12:24:13 batt
39 *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
44 #include <cfg/arch_config.h>
45 #include <drv/timer.h>
47 /** Flag di stato del display */
48 #define LCDF_BUSY BV(7)
51 * Addresses of LCD display character positions, expanded
52 * for faster access (DB7 = 1).
54 static const uint8_t lcd_address[] =
57 0x80, 0x81, 0x82, 0x83,
58 0x84, 0x85, 0x86, 0x87,
59 0x88, 0x89, 0x8A, 0x8B,
60 0x8C, 0x8D, 0x8E, 0x8F,
62 0x90, 0x91, 0x92, 0x93,
66 0xC0, 0xC1, 0xC2, 0xC3,
67 0xC4, 0xC5, 0xC6, 0xC7,
68 0xC8, 0xC9, 0xCA, 0xCB,
69 0xCC, 0xCD, 0xCE, 0xCF,
71 0xD0, 0xD1, 0xD2, 0xD3,
76 0x94, 0x95, 0x96, 0x97,
77 0x98, 0x99, 0x9A, 0x9B,
78 0x9C, 0x9D, 0x9E, 0x9F,
79 0xA0, 0xA1, 0xA2, 0xA3,
81 0xA4, 0xA5, 0xA6, 0xA7,
85 0xD4, 0xD5, 0xD6, 0xD7,
86 0xD8, 0xD9, 0xDA, 0xDB,
87 0xDC, 0xDD, 0xDE, 0xDF,
88 0xE0, 0xE1, 0xE2, 0xE3,
90 0xE4, 0xE5, 0xE6, 0xE7,
93 #endif /* LCD_ROWS > 2 */
96 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
99 * Current display position. We remember this to optimize
100 * LCD output by avoiding to set the address every time.
102 static lcdpos_t lcd_current_addr;
105 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
106 /* __________________
109 * R/W __________________
113 * DATA -<================
115 INLINE void lcd_dataWrite(uint8_t data)
118 /* Write high nibble */
125 /* Write low nibble */
132 #else /* !CONFIG_LCD_4BIT */
141 #endif /* !CONFIG_LCD_4BIT */
144 /* __________________
153 INLINE uint8_t lcd_dataRead(void)
158 LCD_DB_IN; /* Set bus as input! */
163 /* Read high nibble */
170 /* Read low nibble */
177 #else /* !CONFIG_LCD_4BIT */
186 #endif /* !CONFIG_LCD_4BIT */
189 LCD_DB_OUT; /* Reset bus as output! */
197 * READ __________________
201 * DATA --<===============
203 INLINE void lcd_regWrite(uint8_t data)
219 INLINE uint8_t lcd_regRead(void)
224 data = lcd_dataRead();
231 INLINE void lcd_mode4Bit(void)
235 LCD_WRITE_H(LCD_CMD_SETFUNC);
244 #endif /* CONFIG_LCD_4BIT */
246 #else /* ARCH_EMUL */
248 extern void Emul_LCDWriteReg(uint8_t d);
249 extern uint8_t Emul_LCDReadReg(void);
250 extern void Emul_LCDWriteData(uint8_t d);
251 extern uint8_t Emul_LCDReadData(void);
253 #define lcd_regWrite(d) Emul_LCDWriteReg(d)
254 #define lcd_regRead(d) Emul_LCDReadReg()
255 #define lcd_dataWrite(d) Emul_LCDWriteData(d)
256 #define lcd_dataRead(d) Emul_LCDReadData()
258 #endif /* ARCH_EMUL */
262 * Wait until the LCD busy flag clears.
264 void lcd_waitBusy(void)
268 uint8_t val = lcd_regRead();
269 if (!(val & LCDF_BUSY))
276 * Move the cursor to \a addr, only if not already there.
278 void lcd_moveTo(uint8_t addr)
280 if (addr != lcd_current_addr)
283 lcd_regWrite(lcd_address[addr]);
284 lcd_current_addr = addr;
290 * Write a value in LCD data register, waiting for the busy flag.
292 void lcd_setReg(uint8_t val)
298 #include <cfg/debug.h>
300 * Write the character \a c on display address \a addr.
302 * NOTE: argh, the HD44 lcd type is a bad beast: our
303 * move/write -> write optimization requires this mess
304 * because display lines are interleaved!
306 void lcd_putc(uint8_t addr, uint8_t c)
308 if (addr != lcd_current_addr)
309 lcd_setReg(lcd_address[addr]);
313 lcd_current_addr = addr + 1;
315 /* If we are at end of display wrap the address to 0 */
316 if (lcd_current_addr == LCD_COLS * LCD_ROWS)
317 lcd_current_addr = 0;
319 /* If we are at the end of a row put the cursor at the beginning of the next */
320 if (!(lcd_current_addr % LCD_COLS))
321 lcd_setReg(lcd_address[lcd_current_addr]);
326 * Remap the glyph of a character.
328 * glyph - bitmap of 8x8 bits.
329 * code - must be 0-7 for the Hitachi LCD-II controller.
331 void lcd_remapChar(const char *glyph, char code)
335 /* Set CG RAM address */
336 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
338 /* Write bitmap data */
339 for (i = 0; i < 8; i++)
342 lcd_dataWrite(glyph[i]);
345 /* Move back to original address */
346 lcd_setReg(lcd_address[lcd_current_addr]);
351 void lcd_remapfont(void)
353 static const char lcd_glyphs[8] =
355 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
359 for (i = 0; i < 15; i++)
360 lcd_remapChar(i, bernie_char);
363 lcd_setAddr(lcd_DefLayer, 0);
364 for (i = 0; i < 80; i++)
365 lcd_putCharUnlocked(i);
369 void lcd_hw_init(void)
378 #endif /* CONFIG_LCD_4BIT */
380 lcd_regWrite(LCD_CMD_SETFUNC);
383 lcd_regWrite(LCD_CMD_DISPLAY_ON);
386 lcd_regWrite(LCD_CMD_CLEAR);
390 lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
392 lcd_regWrite(LCD_CMD_DISPLAYMODE);
398 void lcd_hw_test(void)
400 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
402 kprintf("3 -> %02X\n", lcd_regRead());
405 for (int i = 0; i < 10; i++)
409 kprintf("addr = %02X\n", lcd_regRead());
413 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
415 kprintf("4A -> %02X\n", lcd_regRead());
418 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
420 kprintf("52 -> %02X\n", lcd_regRead());
423 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
425 kprintf("1F -> %02X\n", lcd_regRead());
429 #endif /* CONFIG_TEST */