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.4 2007/10/01 10:46:09 batt
18 *#* Add light LCD position computation.
20 *#* Revision 1.3 2006/09/20 19:55:01 marco
21 *#* Added CONFIG_LCD_4BIT.
23 *#* Revision 1.2 2006/07/19 12:56:25 bernie
24 *#* Convert to new Doxygen style.
26 *#* Revision 1.1 2005/11/04 18:00:42 bernie
27 *#* Import into DevLib.
29 *#* Revision 1.2 2005/06/14 14:43:43 bernie
30 *#* Add DevLib headers.
32 *#* Revision 1.1 2005/05/24 09:17:58 batt
33 *#* Move drivers to top-level.
35 *#* Revision 1.9 2005/05/09 21:58:53 batt
38 *#* Revision 1.8 2005/05/09 12:52:46 batt
39 *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
41 *#* Revision 1.7 2005/05/09 12:24:13 batt
42 *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
47 #include <cfg/arch_config.h>
48 #include <drv/timer.h>
50 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
51 #define CONFIG_LCD_4BIT 1
52 #elif defined(LCD_READ) && defined(LCD_WRITE)
53 #define CONFIG_LCD_4BIT 0
55 #error Incomplete or missing LCD_READ/LCD_WRITE macros
58 /** Flag di stato del display */
59 #define LCDF_BUSY BV(7)
61 #if CONFIG_LCD_ADDRESS_FAST == 1
62 #define lcd_address(x) lcd_address[x]
64 * Addresses of LCD display character positions, expanded
65 * for faster access (DB7 = 1).
67 static const uint8_t lcd_address[] =
70 0x80, 0x81, 0x82, 0x83,
71 0x84, 0x85, 0x86, 0x87,
72 0x88, 0x89, 0x8A, 0x8B,
73 0x8C, 0x8D, 0x8E, 0x8F,
75 0x90, 0x91, 0x92, 0x93,
79 0xC0, 0xC1, 0xC2, 0xC3,
80 0xC4, 0xC5, 0xC6, 0xC7,
81 0xC8, 0xC9, 0xCA, 0xCB,
82 0xCC, 0xCD, 0xCE, 0xCF,
84 0xD0, 0xD1, 0xD2, 0xD3,
89 0x94, 0x95, 0x96, 0x97,
90 0x98, 0x99, 0x9A, 0x9B,
91 0x9C, 0x9D, 0x9E, 0x9F,
92 0xA0, 0xA1, 0xA2, 0xA3,
94 0xA4, 0xA5, 0xA6, 0xA7,
98 0xD4, 0xD5, 0xD6, 0xD7,
99 0xD8, 0xD9, 0xDA, 0xDB,
100 0xDC, 0xDD, 0xDE, 0xDF,
101 0xE0, 0xE1, 0xE2, 0xE3,
103 0xE4, 0xE5, 0xE6, 0xE7,
106 #endif /* LCD_ROWS > 2 */
109 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
110 #else /* CONFIG_LCD_ADDRESS_FAST == 0 */
112 static uint8_t col_address[] =
123 * Addresses of LCD display character positions, calculated runtime to save RAM
125 static uint8_t lcd_address(uint8_t addr)
127 return col_address[addr / LCD_COLS] + addr % LCD_COLS;
129 #endif /* CONFIG_LCD_ADDRESS_FAST */
132 * Current display position. We remember this to optimize
133 * LCD output by avoiding to set the address every time.
135 static lcdpos_t lcd_current_addr;
138 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
139 /* __________________
142 * R/W __________________
146 * DATA -<================
148 INLINE void lcd_dataWrite(uint8_t data)
151 /* Write high nibble */
158 /* Write low nibble */
165 #else /* !CONFIG_LCD_4BIT */
174 #endif /* !CONFIG_LCD_4BIT */
177 /* __________________
186 INLINE uint8_t lcd_dataRead(void)
191 LCD_DB_IN; /* Set bus as input! */
196 /* Read high nibble */
203 /* Read low nibble */
210 #else /* !CONFIG_LCD_4BIT */
219 #endif /* !CONFIG_LCD_4BIT */
222 LCD_DB_OUT; /* Reset bus as output! */
230 * READ __________________
234 * DATA --<===============
236 INLINE void lcd_regWrite(uint8_t data)
252 INLINE uint8_t lcd_regRead(void)
257 data = lcd_dataRead();
264 INLINE void lcd_mode4Bit(void)
268 LCD_WRITE_H(LCD_CMD_SETFUNC);
277 #endif /* CONFIG_LCD_4BIT */
279 #else /* ARCH_EMUL */
281 extern void Emul_LCDWriteReg(uint8_t d);
282 extern uint8_t Emul_LCDReadReg(void);
283 extern void Emul_LCDWriteData(uint8_t d);
284 extern uint8_t Emul_LCDReadData(void);
286 #define lcd_regWrite(d) Emul_LCDWriteReg(d)
287 #define lcd_regRead(d) Emul_LCDReadReg()
288 #define lcd_dataWrite(d) Emul_LCDWriteData(d)
289 #define lcd_dataRead(d) Emul_LCDReadData()
291 #endif /* ARCH_EMUL */
295 * Wait until the LCD busy flag clears.
297 void lcd_waitBusy(void)
301 uint8_t val = lcd_regRead();
302 if (!(val & LCDF_BUSY))
309 * Move the cursor to \a addr, only if not already there.
311 void lcd_moveTo(uint8_t addr)
313 if (addr != lcd_current_addr)
316 lcd_regWrite(lcd_address(addr));
317 lcd_current_addr = addr;
323 * Write a value in LCD data register, waiting for the busy flag.
325 void lcd_setReg(uint8_t val)
331 #include <cfg/debug.h>
333 * Write the character \a c on display address \a addr.
335 * NOTE: argh, the HD44 lcd type is a bad beast: our
336 * move/write -> write optimization requires this mess
337 * because display lines are interleaved!
339 void lcd_putc(uint8_t addr, uint8_t c)
341 if (addr != lcd_current_addr)
342 lcd_setReg(lcd_address(addr));
346 lcd_current_addr = addr + 1;
348 /* If we are at end of display wrap the address to 0 */
349 if (lcd_current_addr == LCD_COLS * LCD_ROWS)
350 lcd_current_addr = 0;
352 /* If we are at the end of a row put the cursor at the beginning of the next */
353 if (!(lcd_current_addr % LCD_COLS))
354 lcd_setReg(lcd_address(lcd_current_addr));
359 * Remap the glyph of a character.
361 * glyph - bitmap of 8x8 bits.
362 * code - must be 0-7 for the Hitachi LCD-II controller.
364 void lcd_remapChar(const char *glyph, char code)
368 /* Set CG RAM address */
369 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
371 /* Write bitmap data */
372 for (i = 0; i < 8; i++)
375 lcd_dataWrite(glyph[i]);
378 /* Move back to original address */
379 lcd_setReg(lcd_address(lcd_current_addr));
384 void lcd_remapfont(void)
386 static const char lcd_glyphs[8] =
388 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
392 for (i = 0; i < 15; i++)
393 lcd_remapChar(i, bernie_char);
396 lcd_setAddr(lcd_DefLayer, 0);
397 for (i = 0; i < 80; i++)
398 lcd_putCharUnlocked(i);
402 void lcd_hw_init(void)
411 #endif /* CONFIG_LCD_4BIT */
413 lcd_regWrite(LCD_CMD_SETFUNC);
416 lcd_regWrite(LCD_CMD_DISPLAY_ON);
419 lcd_regWrite(LCD_CMD_CLEAR);
423 lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
425 lcd_regWrite(LCD_CMD_DISPLAYMODE);
431 void lcd_hw_test(void)
433 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
435 kprintf("3 -> %02X\n", lcd_regRead());
438 for (int i = 0; i < 10; i++)
442 kprintf("addr = %02X\n", lcd_regRead());
446 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
448 kprintf("4A -> %02X\n", lcd_regRead());
451 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
453 kprintf("52 -> %02X\n", lcd_regRead());
456 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
458 kprintf("1F -> %02X\n", lcd_regRead());
462 #endif /* CONFIG_TEST */