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.5 2007/10/01 18:59:27 batt
18 *#* Set to const col_address; add static assert check on array dimension.
20 *#* Revision 1.4 2007/10/01 10:46:09 batt
21 *#* Add light LCD position computation.
23 *#* Revision 1.3 2006/09/20 19:55:01 marco
24 *#* Added CONFIG_LCD_4BIT.
26 *#* Revision 1.2 2006/07/19 12:56:25 bernie
27 *#* Convert to new Doxygen style.
29 *#* Revision 1.1 2005/11/04 18:00:42 bernie
30 *#* Import into DevLib.
32 *#* Revision 1.2 2005/06/14 14:43:43 bernie
33 *#* Add DevLib headers.
35 *#* Revision 1.1 2005/05/24 09:17:58 batt
36 *#* Move drivers to top-level.
38 *#* Revision 1.9 2005/05/09 21:58:53 batt
41 *#* Revision 1.8 2005/05/09 12:52:46 batt
42 *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
44 *#* Revision 1.7 2005/05/09 12:24:13 batt
45 *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
50 #include <cfg/arch_config.h>
51 #include <drv/timer.h>
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
58 #error Incomplete or missing LCD_READ/LCD_WRITE macros
61 /** Flag di stato del display */
62 #define LCDF_BUSY BV(7)
64 #if CONFIG_LCD_ADDRESS_FAST == 1
65 #define lcd_address(x) lcd_address[x]
67 * Addresses of LCD display character positions, expanded
68 * for faster access (DB7 = 1).
70 static const uint8_t lcd_address[] =
73 0x80, 0x81, 0x82, 0x83,
74 0x84, 0x85, 0x86, 0x87,
75 0x88, 0x89, 0x8A, 0x8B,
76 0x8C, 0x8D, 0x8E, 0x8F,
78 0x90, 0x91, 0x92, 0x93,
82 0xC0, 0xC1, 0xC2, 0xC3,
83 0xC4, 0xC5, 0xC6, 0xC7,
84 0xC8, 0xC9, 0xCA, 0xCB,
85 0xCC, 0xCD, 0xCE, 0xCF,
87 0xD0, 0xD1, 0xD2, 0xD3,
92 0x94, 0x95, 0x96, 0x97,
93 0x98, 0x99, 0x9A, 0x9B,
94 0x9C, 0x9D, 0x9E, 0x9F,
95 0xA0, 0xA1, 0xA2, 0xA3,
97 0xA4, 0xA5, 0xA6, 0xA7,
101 0xD4, 0xD5, 0xD6, 0xD7,
102 0xD8, 0xD9, 0xDA, 0xDB,
103 0xDC, 0xDD, 0xDE, 0xDF,
104 0xE0, 0xE1, 0xE2, 0xE3,
106 0xE4, 0xE5, 0xE6, 0xE7,
109 #endif /* LCD_ROWS > 2 */
112 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
113 #else /* CONFIG_LCD_ADDRESS_FAST == 0 */
115 static const uint8_t col_address[] =
124 STATIC_ASSERT(countof(col_address) == LCD_ROWS);
126 * Addresses of LCD display character positions, calculated runtime to save RAM
128 static uint8_t lcd_address(uint8_t addr)
130 return col_address[addr / LCD_COLS] + addr % LCD_COLS;
132 #endif /* CONFIG_LCD_ADDRESS_FAST */
135 * Current display position. We remember this to optimize
136 * LCD output by avoiding to set the address every time.
138 static lcdpos_t lcd_current_addr;
141 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
142 /* __________________
145 * R/W __________________
149 * DATA -<================
151 INLINE void lcd_dataWrite(uint8_t data)
154 /* Write high nibble */
161 /* Write low nibble */
168 #else /* !CONFIG_LCD_4BIT */
177 #endif /* !CONFIG_LCD_4BIT */
180 /* __________________
189 INLINE uint8_t lcd_dataRead(void)
194 LCD_DB_IN; /* Set bus as input! */
199 /* Read high nibble */
206 /* Read low nibble */
213 #else /* !CONFIG_LCD_4BIT */
222 #endif /* !CONFIG_LCD_4BIT */
225 LCD_DB_OUT; /* Reset bus as output! */
233 * READ __________________
237 * DATA --<===============
239 INLINE void lcd_regWrite(uint8_t data)
255 INLINE uint8_t lcd_regRead(void)
260 data = lcd_dataRead();
267 INLINE void lcd_mode4Bit(void)
271 LCD_WRITE_H(LCD_CMD_SETFUNC);
280 #endif /* CONFIG_LCD_4BIT */
282 #else /* ARCH_EMUL */
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);
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()
294 #endif /* ARCH_EMUL */
298 * Wait until the LCD busy flag clears.
300 void lcd_waitBusy(void)
304 uint8_t val = lcd_regRead();
305 if (!(val & LCDF_BUSY))
312 * Move the cursor to \a addr, only if not already there.
314 void lcd_moveTo(uint8_t addr)
316 if (addr != lcd_current_addr)
319 lcd_regWrite(lcd_address(addr));
320 lcd_current_addr = addr;
326 * Write a value in LCD data register, waiting for the busy flag.
328 void lcd_setReg(uint8_t val)
334 #include <cfg/debug.h>
336 * Write the character \a c on display address \a addr.
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!
342 void lcd_putc(uint8_t addr, uint8_t c)
344 if (addr != lcd_current_addr)
345 lcd_setReg(lcd_address(addr));
349 lcd_current_addr = addr + 1;
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;
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));
362 * Remap the glyph of a character.
364 * glyph - bitmap of 8x8 bits.
365 * code - must be 0-7 for the Hitachi LCD-II controller.
367 void lcd_remapChar(const char *glyph, char code)
371 /* Set CG RAM address */
372 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
374 /* Write bitmap data */
375 for (i = 0; i < 8; i++)
378 lcd_dataWrite(glyph[i]);
381 /* Move back to original address */
382 lcd_setReg(lcd_address(lcd_current_addr));
387 void lcd_remapfont(void)
389 static const char lcd_glyphs[8] =
391 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
395 for (i = 0; i < 15; i++)
396 lcd_remapChar(i, bernie_char);
399 lcd_setAddr(lcd_DefLayer, 0);
400 for (i = 0; i < 80; i++)
401 lcd_putCharUnlocked(i);
405 void lcd_hw_init(void)
414 #endif /* CONFIG_LCD_4BIT */
416 lcd_regWrite(LCD_CMD_SETFUNC);
419 lcd_regWrite(LCD_CMD_DISPLAY_ON);
422 lcd_regWrite(LCD_CMD_CLEAR);
426 lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
428 lcd_regWrite(LCD_CMD_DISPLAYMODE);
434 void lcd_hw_test(void)
436 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
438 kprintf("3 -> %02X\n", lcd_regRead());
441 for (int i = 0; i < 10; i++)
445 kprintf("addr = %02X\n", lcd_regRead());
449 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
451 kprintf("4A -> %02X\n", lcd_regRead());
454 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
456 kprintf("52 -> %02X\n", lcd_regRead());
459 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
461 kprintf("1F -> %02X\n", lcd_regRead());
465 #endif /* CONFIG_TEST */